* 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 ** 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.