From cf8a3f15ee1c80b874be10cbdd34496b84560f59 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Tue, 14 Jan 2025 22:48:35 +0100 Subject: Sort guides up a bit --- guides/cloud/vps.org | 198 --------------------------------------------------- 1 file changed, 198 deletions(-) delete mode 100644 guides/cloud/vps.org (limited to 'guides/cloud/vps.org') diff --git a/guides/cloud/vps.org b/guides/cloud/vps.org deleted file mode 100644 index 986e373..0000000 --- a/guides/cloud/vps.org +++ /dev/null @@ -1,198 +0,0 @@ -* Security -** Switch APT to HTTPS -~sudo sed -i 's/http:/https:/' /etc/apt/sources.list~ - -Granted, the repository signature provides enough protection; still, -no sense in wasting bandwidth and CPU if someone is meddling. -** Tweak root access -On OVH's Debian image: -- The =root= account has no password. -- =PermitRootLogin= defaults to =prohibit-password=: set it to =no=. -** Enable fail2ban -~lastb~ says there's about 4000 login attempts per day; that makes -=/var/log/btmp= much bigger than it needs to be. - -Debian's fail2ban comes with a jail for ~sshd~, so it's just a matter -of ~apt install fail2ban~. -** Tweak user accounts -=debian= seems mildly popular among bots looking for valid usernames. - -Ideally I'd just rename the =debian= account, but renaming does not -seem to be a very well-defined operation: ~usermod --login $name ---move-home --home /home/$name debian~ gets partway there, but leaves -a bunch of miscellany to take care of (e.g. sudoers). - -So instead, I'll -- create my own user account: ~sudo adduser $name~ -- add it to all groups =debian= belongs to: - #+begin_src sh - groups=$(groups | tr ' ' '\n' | grep -v debian | paste -sd,) - sudo usermod --append --groups ${groups} ${name} - #+end_src -- only allow password authentication over SSH for this new user - account: - #+begin_src conf - PasswordAuthentication no - Match User … - PasswordAuthentication yes - #+end_src - -* System -#+begin_src sh -sudo hostnamectl set-hostname $DOMAIN -sudo timedatectl set-timezone $tz -#+end_src - -* Services -** Web server -Run ~sudo apt install nginx~; then, in -=/etc/nginx/sites-available/$DOMAIN=: -#+begin_src conf -server { - listen 80; - listen [::]:80; - - server_name $DOMAIN www.$DOMAIN; - access_log /var/log/nginx/$DOMAIN.access.log; - - root /var/www/$DOMAIN/html; - index index.html; - - location / { - try_files $uri $uri/ =404; - } -} -#+end_src -Use one =access_log= file per site, to simplify analytics. - -Run ~sudo systemctl restart nginx~. -*** fail2ban -With the following files in =$HOME=: -#+begin_src conf -# nginx-botsearch.local -[Init] - -block = \S*(php|wp-|wordpress|jenkins|hudson|sql|boaform)[^,]* - -[Definition] - -# Change from distro: just remove the leading slash before . -failregex = ^ \- \S+ \[\] \"(GET|POST|HEAD) \S+\" 404 .+$ - ^ \[error\] \d+#\d+: \*\d+ (\S+ )?\"\S+\" (failed|is not found) \(2\: No such file or directory\), client\: \, server\: \S*\, request: \"(GET|POST|HEAD) \/ \S+\"\, .*?$ - -# jail.local -[nginx-http-auth] -enabled = true - -[nginx-botsearch] -enabled = true -# Assume that each requests to $DOMAIN will be logged to "$DOMAIN.access.log". -logpath = /var/log/nginx/*access.log -#+end_src - -Then: -#+begin_src sh -sudo cp ~/nginx-botsearch.local /etc/fail2ban/filter.d/ -sudo cp ~/jail.local /etc/fail2ban/ -sudo systemctl restart fail2ban -#+end_src - -Check how these rules fare against real bot searches with: -#+begin_src sh -fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-botsearch.local -#+end_src - -*** HTTPS -#+begin_src sh -sudo apt install certbot python3-certbot-nginx -sudo certbot --nginx -d $DOMAIN www.$DOMAIN -sudo systemctl reload nginx -#+end_src - -** Git server -*** SSH access -#+begin_src sh -sudo apt install git -sudo tee -a /etc/shells <<< $(which git-shell) -sudo adduser git --disabled-password --shell $(which git-shell) -sudo mkdir /srv/git -sudo chown git:git /srv/git -# For every new repo: -sudo -u git git init --bare --shared=group /srv/git/${repo} -#+end_src - -*** Web mirror -With =/etc/nginx/sites-available/git.$DOMAIN=: -#+begin_src conf -server { - listen 80; - listen [::]:80; - - server_name git.$DOMAIN; - access_log /var/log/nginx/git.$DOMAIN.access.log; - - root /usr/share/cgit; - try_files $uri @cgit; - - location @cgit { - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; - fastcgi_param PATH_INFO $uri; - fastcgi_param QUERY_STRING $args; - fastcgi_param HTTP_HOST $server_name; - fastcgi_pass unix:/run/fcgiwrap.socket; - } -} -#+end_src - -And =/etc/cgitrc/=: -#+begin_src conf -css=/cgit.css -logo=/cgit.png - -virtual-root=/ -# Change to https:// after setting up certbot: -clone-url=http://git.$DOMAIN/$CGIT_REPO_URL -snapshots=tar.xz - -enable-git-config=1 -enable-http-clone=1 -enable-index-owner=0 - -scan-path=/srv/git -#+end_src - -In each repository: -- fill in =description=, -- fill =[cgit]= section in =config= (=hide=, =owner=, =section=). - -Do: -#+begin_src sh -sudo apt install cgit fcgiwrap -( cd /etc/sites-enabled/ && ln -s ../sites-avaiable/git.$DOMAIN . ) -sudo systemctl restart nginx -# Make fail2ban notice the new log file. -sudo systemctl restart fail2ban -#+end_src - -**** "Idle" vs default branch -cgit struggles to guess what to print for the "Idle" column on the -index page when the default branch is not "master". [[https://lists.zx2c4.com/pipermail/cgit/2020-August/004515.html][Workarounds]]: - -- set =repo.defbranch=, -- update =agefile= with [[https://git.zx2c4.com/cgit/tree/contrib/hooks/post-receive.agefile][a post-receive hook]]. -** CGI -I like the idea of [[https://en.wikipedia.org/wiki/Common_Gateway_Interface#Using_CGI_scripts][CGI "scripts"]], i.e. having the web server fire a -program to handle requests: - -- URI bits are passed through environment variables and stdin; -- the program spits the page on stdout. - -Had some fun toying with Python's ~cgi~ module; sadly though the -project has [[https://peps.python.org/pep-0594/#cgi][decided to deprecate it]]. The docs [[https://docs.python.org/3.11/library/cgi.html][suggest some migration -paths]], and there's a [[https://pypi.org/project/legacy-cgi/][legacy-cgi package on PyPI]] if I really want to -keep using it I guess. - -Also nginx has no support for CGI either, though their documentation -explains how to combine their FastCGI support with ~fcgiwrap~ to -enable CGI scripts. -- cgit v1.2.3