============ SERVER NOTES ============ For that pre-installation task of choosing a name for your server, see the ancient RFC 1178 Choosing a Name for Your Computer. I prefer to name my servers after trees. ==================== Initial Installation ==================== If you wish to install recent Debian versions with sysvinit instead of systemd, you should do the following: At the installation menu, "tab" on your choice of installation methods and append the following to the boot options: preseed/late_command="in-target apt-get install -y sysvinit-core" Launch the installation and continue as normal. SSHD Configuration After you have set up an ordinary user who can su to the root user (i.e., is a member of the wheel group in FreeBSD), you should disable root logins, by adding the following line: PermitRootLogin no to your /etc/ssh/sshd_config file. If you are slightly more adventurous, you could deny password logins by the root user, but allow root to login using an SSH key: PermitRootLogin prohibit-password If you are less adventurous, you could deny password logins to everyone and require all users to login using an SSH key: PubkeyAuthentication yes # This is often the default PasswordAuthentication no # This is often the default ChallengeResponseAuthentication no # This is often NOT the default Of course, you should make sure that key logins are working before disabling password logins. Even after you disable ChallengeResponseAuthentication you should probably leave UsePAM set to yes, because PAM controls more than login authentication. To enable key login for a user, add the user's SSH public key to the file: ~/.ssh/authorized_keys Some additional steps you can take to restrict SSH logins even more are limiting which user groups are permitted to connect via SSH and reducing the time that users have to complete their login transaction before being requested to try again. Create an ssh-users user group: addgroup --gid 600 ssh-users Add the appropriate users to the ssh-users group: usermod -a -G ssh-users user-name Restrict SSH login to members of that group in your /etc/ssh/sshd_config file: AllowGroups ssh-users Reduce the login grace time from the default two minutes to thirty seconds: LoginGraceTime 30 ================================ Miscellaneous Intial Setup Tasks ================================ Some initial tasks you might need to do on some VPSs with minimal Debian installations: dpkg-reconfigure locales, install bsdutils, debian-keyring, debian-archive-keyring, dialog, apt-utils, man-db, manpages and openssl. You might also want to run ssh-keygen -A, which generates host keys for any key type that does not already exist. (In some rare cases, you may need to change the permissions of /dev/tty to 0666 in order to get mksh to work.) Lower the system load average under FreeBSD: # sysctl kern.eventtimer.periodic=1 You can make the above sysctl change permanent by adding the line: kern.eventtimer.periodic=1 to your /etc/sysctl.conf file. To completely disable sendmail in FreeBSD, add the following lines: sendmail_enable="NONE" sendmail_submit_enable="NO" sendmail_outbound_enable="NO" sendmail_msp_queue_enable="NO" to the /etc/rc.conf file. Adding Static IPv6 Debian (/etc/network/interfaces) iface ens3 inet6 static address 0:0:0:0::0 netmask 64 gateway 0:0:0::1 or, replace the "gateway" line with: post-up /sbin/ip -6 route add 0:0:0::1 dev ens3 post-up /sbin/ip -6 route add default via 0:0:0::1 dev ens3 pre-down /sbin/ip -6 route del default via 0:0:0::1 dev ens3 pre-down /sbin/ip -6 route del 0:0:0::1 dev ens3 FreeBSD (/etc/rc.conf) The following template shows how to add two IPv6 addresses on a BuyVM slice. Notice that for the second IPv6 address, the ipv6 suffix is not added to the interface name. It is simply ...em0_alias0, not ...em0_ipv6_alias0. ipv6_activate_all_interfaces="YES" ifconfig_em0_ipv6="inet6 0:0:0:0::2 prefixlen 48" ifconfig_em0_alias0="inet6 0:0:0:0::3 prefixlen 48" ipv6_defaultrouter="0:0:0::1" OpenBSD Create /etc/mygate file with the defaultrouter address. 0:0:0:0::1 Edit /etc/hostname.xnf0 to include the IPv6 address and the prefixlen. The "dhcp" line is for IPv4 and was created during the OS installation. inet6 0:0:0:0:0:0:fe:fef 64 dhcp Restart the network with: # sh /etc/netstart The netmask (prefixlen) is 64 at Hetzner, OVH, prgmr.com, and Ramnode, 112 at TinyKVM, and 48 at BuyVM and Veesp. Resizing your Debian / partition at OVH ======================================= Reboot into rescue mode. SSH into rescue environment. lsblk umount /dev/sdb1 fsck -fy /dev/sdb1 resize2fs /dev/sdb1 4320M fsck -fy /dev/sdb1 fdisk /dev/sdb p - print partition table d - delete partition n - create new partition - default start block - end block: +4320M w - write new partition table and exit fsck -fy /dev/sdb1 fdisk /dev/sdb p - print partition table n - create whatever new partitions you need Reboot in normal mode. You can resize the / partition on a *SCALEWAY* VPS in a similar fashion, but you will need to do a couple of additional steps before you reboot. First, you will need to chroot into the installed system: mount /dev/vda1 /mnt chroot /mnt cd /etc You will then need to edit the fstab file to use device names instead of block IDs because the block ID of /dev/vda1 will have changed after the resizing. You will also need to change the error behavior of the efi boot partition: /dev/vda1 / ext4 rw,relatime 0 1 /dev/vda15 /boot/efi vfat rw,relatime,errors=continue 0 0 Now, re-set the server to boot from the hard drive, and reboot. Resizing your FreeBSD / partition at OVH ======================================== On the OVH VPS models that support FreeBSD, the template installation provides a file system of only 4G. You will need to resize the file system following the instructions in the OVH guide. https://docs.ovh.com/us/en/public-cloud/resize-file-system-freebsd-12-instance/ sudo gpart show sudo gpart recover vtbd0 sudo gpart show sudo gpart resize -i 2 vtbd0 Adding a Second Disk under FreeBSD ================================== gpart add -t freebsd da0 da0s1 added newfs -U /dev/da0s1 By default, FreeBSD's UFS file system reserves 8% for itself. The documentation says that setting this to 5% or less causes "space optimization to always be used which will greatly increase the overhead for file writes." Adding a New User ================= Under both Debian and FreeBSD the adduser utility is used to add new users to the system. Under Debian: # adduser [new-user-name] Under FreeBSD: # adduser and then follow the prompts. Debian populates the new user's home directory from /etc/skel. FreeBSD uses /usr/share/skel. When you install the mksh package it will create a sample ~/.mkshrc file in /etc/skel under Debian and in /usr/local/share/examples/mksh under FreeBSD. Some Errors I have encountered at Kimsufi on fresh FreeBSD installations ======================================================================== (1) FreeBSD Update Error on Kimsufi Caused by Kimsufi's default /etc/resolv.conf Replace resolv.conf with your own file: nameserver 1.1.1.1 nameserver 1.0.0.1 and the problem goes away. (2) FreeBSD adduser error Error adding new user - pw: user 'oldfolio' disappeared during update This issue is not common. And it’s caused by databases being out of sync. To fix this issue, just run: /usr/sbin/pwd_mkdb -p /etc/master.passwd Solution taken from this site. (3) FreeBSD pkg update error By default, Kimsufi's FreeBSD installations are set to use OVH's own pkg repository, configured here: /usr/local/etc/pkg/repos/OVH.conf This repository is not always up to date. So, I disable it (by changing the file extension to anything other than .conf). ========================== Setting Up a Gopher Server ========================== Install pygopherd. The default configuration (on Debian systems found at /etc/pygopherd/pygopherd.conf, on FreeBSD systems found at /usr/local/etc/pygopherd/pygopherd.conf) should work fine but read it anyway so that you understand what pygopherd is doing. Pygopherd will serve files from the /var/gopher directory. All files in that directory (and its subdirectories) must belong to owner gopher and group gopher. Under FreeBSD, an easy way to start the gopher server automatically on system reboots is to add to the root user’s crontab: @reboot /usr/local/bin/pygopherd One thing to notice here is the contrast between the simplicity of setting up a gopher server and the complexity of setting up a web server. BUCKTOOTH If you've installed the bucktooth server instead of pygopherd, you can disable bucktooth with: # update-inetd --disable gopher You can re-enable it later with: # update-inetd --enable gopher GOPHERNICUS UNDER OPENBSD Follow the directions you will find here: /usr/local/share/doc/pkg-readmes/gophernicus Add the following line to /etc/inetd.conf (which you may need to create): gopher stream tcp nowait _gophernicus /usr/local/libexec/in.gophernicus in.gophernicus -h gopher.oldfolio.org Add the following line to /etc/rc.conf.local (which you may need to create): inetd_flags= Restart /etc/rc.d/inetd. For further information, read the documentation found in: /usr/local/share/doc/gophernicus/ ==================== Setting Up Web Sites ==================== Preface Drew Devault has a great article about web site design in which he emphasizes that approaches to design that make a site easier to navigate for visually impaired persons also make the site easier to navigate for everyone. Perhaps his best piece of advice is: Make sure your page is organized so that if read linearly, from start to finish, without CSS, it still makes sense. Avoid littering marketing garbage...throughout your page. General note about serving web sites: If your server only has an IPv6 address, I have found two options for serving sites over IPv4: Use Cloudflare's DNS, and set Cloudflare to proxy. Add an A record for the Netiter proxy service. Setting Up an Nginx Web Server Because of my minimal needs, the Debian package to install is nginx-light. Under FreeBSD, the package to install is nginx-lite. The installation under FreeBSD 11 returns the following message: =================================================================== Recent version of the NGINX introduces dynamic modules support. In FreeBSD ports tree this feature was enabled by default with the DSO knob. Several vendor's and third-party modules have been converted to dynamic modules. Unset the DSO knob builds an NGINX without dynamic modules support. To load a module at runtime, include the new `load_module' directive in the main context, specifying the path to the shared object file for the module, enclosed in quotation marks. When you reload the configuration or restart NGINX, the module is loaded in. It is possible to specify a path relative to the source directory, or a full path, please see https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/ and http://nginx.org/en/docs/ngx_core_module.html#load_module for details. Default path for the NGINX dynamic modules is /usr/local/libexec/nginx. =================================================================== To your FreeBSD /etc/rc.conf file, add the line: nginx_enable="YES" Links to the site configuration files for the active sites that nginx should be serving should be placed in an nginx/sites-enabled directory. Under Debian, the nginx directory will be found under /etc. Under FreeBSD, it will be found under /usr/local/etc. You may also need to create the sites-enabled directory under FreeBSD. You may further need to edit the nginx/nginx.conf file to add an "include" line to tell nginx to use the sites-enabled directory. I usually add the line just below the gzip settings. Debian: include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; FreeBSD: include /usr/local/etc/nginx/conf.d/*.conf; include /usr/local/etc/nginx/sites-enabled/*; Test the new configuration changes: nginx -t If everything is working, reload (or start) nginx: nginx -s reload Site Configuration Files ======================== There is a useful nginx site configuration wizard at digital ocean here: https://www.digitalocean.com/community/tools/nginx A minimal site configuration file will look something like: server { listen 80; listen [::]:80; root /path/to/site-root; server_name www.domain.tld; } The two "listen" lines are necessary if you want the server to listen on both IPv4 and IPv6. Otherwise, the server will listen only on IPv4, returning errors to requests made over IPv6. To redirect a bare domain to the www subdomain, you can use a configuration that looks something like: server { listen 80; listen [::]:80; server_name domain.tld; return 301 http://www.domain.tld; } To serve custom 404 error pages, create a 404.conf file in the nginx/conf.d directory with the line: error_page 404 = /404.html; Likewise, any aspect of site configuration that will be the same across all of your sites can be specified in a file ending with the .conf extention placed in the nginx/conf.d directory. Be careful with the “Content Security Policy” because it can break HTML and CSS styling elements. In any case, you might have a custom.conf file that looks like: error_page 404 = /404.html; add_header Referrer-Policy no-referrer; add_header X-Frame-Options SAMEORIGIN; add_header Content-Security-Policy "default-src 'self';" always; add_header X-Xss-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; If you wish to display a directory listing instead of an index file, you can add the autoindex directive to the directory that you wish to display as a file listing. location /files-directory/ { # If you have a root path defined in any other location block, # such as a Server Side Includes block, then you need to specify # the root path in autoindex blocks. root /path/to/site-root; autoindex on; } Pygopherd will serve your gopher site over HTTP if you point your web browser to port 70. You can use nginx to proxy requests from port 80 (the default http port) to port 70 using a site config file something like what follows: server { root /var/gopher; server_name gopher.oldfolio.org; location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://localhost:70; } } Server Side Includes ==================== For your nginx site config files, use a construction like: location ~ \.html$ { ssi on; } Honor the gods of the Discworld by adding the following header to your server block: server { ... add_header X-Clacks-Overhead "GNU Terry Pratchett"; } OpenBSD: nginx The primary configuration directory is /etc/nginx NOT /usr/local/share/nginx In the OpenBSD nginx package, nginx runs chrooted requiring files to be served from /var/www/htdocs or its subdirectories for virtual hosts. If you wish to serve files from outside of that directory, you can override the above behavior by using the -u switch when you start or reload nginx. nginx -u nginx -u -s reload Of course, the default behavior is more secure. ====================== Adding SSL/TLS Support ====================== I use SSL/TLS certificates from Let's Encrypt. The certbot utility makes it easy to create and manage Let's Encrypt certificates. Under Debian, install the package certbot. Under FreeBSD, install the package py37-certbot. The FreeBSD installation returns the following message: =========================================================================== This port installs the "standalone" client only, which does not use and is not the certbot-auto bootstrap/wrapper script. The simplest form of usage to obtain certificates is: # sudo certbot certonly --standalone -d , [domain2, ... domainN] NOTE: The client requires the ability to bind on TCP port 80 or 443 (depending on the --preferred-challenges option used). If a server is running on that port, it will need to be temporarily stopped so that the standalone server can listen on that port to complete the challenge authentication process. For more information on the 'standalone' mode, see: https://certbot.eff.org/docs/using.html#standalone The certbot plugins to support apache and nginx certificate installation will be made available in the following ports: * Apache plugin: security/py-certbot-apache * Nginx plugin: security/py-certbot-nginx =========================================================================== !! IMPORTANT !!: The default server (usually the first specified site in /etc/nginx/sites-enabled/, and often /etc/nginx/sites-enabled/default) MUST be accessible over HTTPS with a valid certificate for HTTPS to work with any other sites enabled. So, secure that default site first before trying to configure HTTPS for any other sites. It is also important to remember that THE NGINX SERVER MUST BE STOPPED when you are running the stand-alone version of certbot. With nginx stopped, run: certbot certonly --standalone -d domain.tld -d www.domain.tld For multiple domains, you must use multiple -d switches. The -d switch with a comma separated list is no longer supported. You will be prompted to enter an email address for renewal notifications. Unless certbot encounters errors, your new certificate will be found at: /etc/letsencrypt/live/www.domain.tld/fullchain.pem or /usr/local/etc/letsencrypt/live/www.domain.tld/fullchain.pem depending on whether you are running under Debian or FreeBSD. The certificater's private key will be found at either: /etc/letsencrypt/live/www.domain.tld/privkey.pem or /usr/local/etc/letsencrypt/live/wwww.domain.tld/privkey.pem To renew your certificates, stop nginx and run: certbot renew If you wish to test the renewal process, stop nginx and run: certbot renew --dry-run After renewing certificates, you must RELOAD NGINX in order for nginx to pick up the renewed certificates. (Do you need to reload postfix and dovecot as well?) To see what certificates certbot has installed on your system, you can run: certbot certificates To delete an installed certificate, you can run: certbot delete and then select from the returned list of certificates. Or, you could run: certbot delete --cert-name domain.tld In addition to obtaining certificates from Let's Encrypt, you can also use certbot to obtain free certificates from Norwegian certificate authority BuyPass. Just click on the "Get Started" button for instructions. The process is almost exactly the same. The only difference is that you will need to register with BuyPass using the following commmand: certbot register -m 'user@email.com' --agree-tos --server 'https://api.buypass.com/acme/directory' and when you initially request a certificate you will need to append the command line option: --server 'https://api.buypass.com/acme/directory' Renewals should work without any modifications at all to the command for renewing a Let's Encrypt certificate. One other point to keep in mind: BuyPass certificates are good for 180 days as opposed to Let's Encrypt certificates, which are good for 90 days. More recent versions of certbot (i.e., more than the version included in Debian 10) allow you to specify ECDSA keys instead of the default RSA: certbot certonly --standalone -d site.oldfolio.org --key-type ecdsa !! ONE FINAL IMPORTANT NOTE: In order to use TLSv1.3 on your sites under Debian 10, you *MUST* add TLSv1.3 to the ssl_protocols line in your main /etc/nginx/nginx.conf file. Simply adding it your specific site files is *NOT* sufficient. Moreover, you should probably remove older protocols from the ssl_protocols line as well as adding TLSv1.3. The general rule is: If nginx's default site does not connect over TLSv1.3, then neither will any other configured sites, even if they specify TLSv1.3. DH Params ========= If you have not already done so, you will need to create a DH Params key. In the /etc/ssl/ directory, run: openssl dhparam -out dhparams.pem 4096 This may take a long time, but once it is done you should be ready to implement HTTPS. HTTPS Site Configuration ======================== In order to implement HTTPS on one of your sites, create two server blocks in the site configuration file. The first block will redirect HTTP traffic to HTTPS: server { listen 80; listen [::]:80; root /path/to/site-root; server_name www.domain.tld; return 301 https://$server_name$request_uri; error_page 404 /404.html; } The second block is for serving the site over HTTPS. Here is a sample with an abbreviated ssl_ciphers line: server { root /path/to/site-root; server_name www.domain.tld; listen 443 ssl; listen [::]:443 ssl; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256: ... '; ssl_prefer_server_ciphers on; ssl_certificate /etc/letsencrypt/live/www.domain.tld/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/www.domain.tld/privkey.pem; ssl_dhparam /etc/ssl/dhparams.pem; } A more complete example can be found in this file. (For sites behind Cloudflare, see this file.) My examples do not show support for the TLSv1.3 protocol even though it is currently (January 2019) considered the most secure of the TLS protocols. That is because the Debian nginx package does not support the protocol. I have been able to get TLS 1.3 working under FreeBSD 12.1 (by installing the nginx-devel package instead of the standard nginx package). A sample nginx site configuration file is here. For more information about which ciphers and protocols to use, see Mozilla's server side TLS recommendations. Mozilla even has an SSL configuration generator that you can use. To get inline CSS styling to work, add the following to your Content-Security-Policy line in the nginx configuration file for the site: style-src 'nonce-2726c7f26c' The "nonce" indicator is a special content security policy directive, and the string following it ("2726c7f26c") could have been anything. Once you set this in the nginx configuration file add_header Content-Security-Policy "default-src 'self'; img-src 'self'; object-src 'none'; script-src 'self'; style-src 'nonce-2726c7f26c'"; you will need to add the following to the header of the html file serving the styled page: