servnest/DOCS/installation.md
2023-05-19 00:54:04 +02:00

12 KiB

ServNest installation

Notable prerequisites

  • sudo 1.9.10+ (available in Debian 12+)
  • SFTPGo, is usually not available from most distributions (as of january 2023)
  • Ports 22, 53 and 443 on public IPv6 and IPv4 addresses (not required for a local development/testing setup)

Steps

The servnest-mkosi repository contains all the information needed to automatically build systems configured to run ServNest. Configuration files used in this document refer to it's install/ subdirectory.

DNS resolution

A caching, DNSSEC-validating and TLS-forwarding local stub resolver is recommended, e.g. systemd-resolved, Knot Resolver or Unbound. For systemd-resolved, ResolveUnicastSingleLabel=yes is required.

sudo / sudoers

For the HTTP hosting service, ServNest requires to execute some commands as other users through sudo.

The required sudoers configuration is sudoers and can be placed at /etc/sudoers.d/servnest.

Tor

Install the torrc file as your Tor configuration. The %include statement inside it includes configuration files that will be placed inside any subdirectory of /srv/servnest/tor-config/, and is central to the way ServNest uses Tor.

mkdir /srv/servnest/tor-config
chown -R servnest:tor /srv/servnest/tor-config
chmod -R u=rwX,g=rX,o= /srv/servnest/tor-config

mkdir /srv/servnest/tor-keys
chown -R tor: /srv/servnest/tor-keys
chmod -R u=rwX,g=,o= /srv/servnest/tor-keys

If you're using systemd, you might need to override your distribution configuration by placing tor.service.override.conf inside /etc/systemd/system/tor.service.d/.

Knot DNS

A local primary Knot DNS server is used for both the registry and name server services. Knot DNS configuration is inside knot.conf. Change 42053 port to 53 and local IPs to :: and 0.0.0.0 (or specific ones).

For a public server, at least one secondary server should be set up. As zones can be dynamically added and deleted from the primary server, catalog zones should be used. Configuration for a primary and a secondary server can be found respectively at mkosi.extra/etc/knot/knot-primary.conf and mkosi.extra/etc/knot/knot-secondary.conf.

Add user servnest to group knot to allow ServNest to send commands to Knot:

usermod -aG knot servnest

Database configuration

Knot configuration must be dynamic, therefore the configuration must stored in database, using:

sudo -u knot knotc conf-import /etc/knot/knot.conf

The configuration file won't be used by Knot anymore.

Database configuration edition

Database configuration can be changed using knotc conf-* commands, see Knot DNS 3.2 documentation > Operation > Dynamic configuration. If you don't want to use that and don't want the best uptime possible, you can do the following steps to edit configuration through a plaintext file:

  1. Set enabled to false in [reg] and [ns] sections of config.ini
  2. knotc conf-export /etc/knot/knot.conf
  3. Edit /etc/knot/knot.conf
  4. Stop the Knot DNS daemon
  5. sudo -u knot knotc conf-import /etc/knot/knot.conf
  6. Restart the Knot DNS daemon
  7. Check for errors in logs: cat /var/log/knot/knot.log
  8. Reverse the first step to true

Directories

mkdir /srv/servnest/reg /srv/servnest/ns
chown -R servnest:knot /srv/servnest/reg /srv/servnest/ns
chmod -R u=rwX,g=rwX,o= /srv/servnest/reg /srv/servnest/ns

Registry files initialisation

In addition to being described in configuration, registry zone files need to be initialized (i.e. SOA and NS records) inside /srv/servnest/reg/.

ServNest core

Set up the source code inside /srv/servnest/core/:

git clone https://code.antopie.org/servnest/servnest/ /srv/servnest/core

Set permissions (except for .git/ and db/):

chmod -R u=rX,g=rX,o= $(find /srv/servnest/core -mindepth 1 -maxdepth 1 ! -name .git ! -name db)
chown -R servnest:nginx $(find /srv/servnest/core -mindepth 1 -maxdepth 1 ! -name .git ! -name db)

Generate new SQLite database:

sqlite3 /srv/servnest/core/db/servnest.db < /srv/servnest/core/db/schema.sql

Set permissions for database:

chmod -R u=rwX,g=,o= /srv/servnest/core/db
chown -R servnest: /srv/servnest/core/db

Initialize database secret keys:

echo "UPDATE params SET value = '$(openssl rand -hex 16)' WHERE name = 'username_salt';" | sqlite3 /srv/servnest/core/db/servnest.db

Generate gettext translations:

msgfmt /srv/servnest/core/locales/fr/C/LC_MESSAGES/messages.po -o /srv/servnest/core/locales/fr/C/LC_MESSAGES/messages.mo
chmod u=r,g=,o= /srv/servnest/core/locales/fr/C/LC_MESSAGES/messages.mo
chown servnest: /srv/servnest/core/locales/fr/C/LC_MESSAGES/messages.mo

PHP

In addition to PHP itself, the following PHP extensions are required and their packages probably needs to be installed:

  • pdo
  • pdo_sqlite
  • libsodium
  • gettext
  • curl (only for the check.php script)

You might also want to enable the OPcache extension to improve performance.

php.ini

Set appropriately your php.ini to either php.ini-production or php.ini-development (distributions usually ship php.ini-production as the default php.ini).

Use php.ini as additional PHP configuration (e.g. in /etc/php/conf.d/servnest.ini).

php-fpm.conf

Use php-fpm.conf as the PHP-FPM configuration (e.g. in /etc/php/php-fpm.d/servnest.conf).

For systemd

php-fpm.service.override.conf may be required as the PHP-FPM service configuration override.

Certbot

If you are setting up a testing environment, running certbot commands in this document without --test-cert is probably useless.

Register an ACME account for Let's Encrypt (production and staging):

certbot register --no-eff-email
certbot register --no-eff-email --test-cert

Copy and adapt certbot.ini in /etc/letsencrypt/cli.ini

Install the Certbot deploy hook:

cp certbot-deploy-hook.sh /root/certbot-deploy-hook.sh
chmod +x /root/certbot-deploy-hook.sh

nginx

nginx is used for 2 purposes:

  • serving the PHP interface
  • acting as a reverse proxy before Apache, terminating TLS and enforcing headers policy

Create the ACME HTTP challenge directory used by Certbot:

mkdir /srv/servnest/acme
chown nginx: /srv/servnest/acme
chmod u=rX,g=,o= /srv/servnest/acme

Generate default self-signed certificates:

openssl req -subj '/' -new -newkey RSA:3072 -days 3650 -nodes -x509 -keyout /etc/ssl/private/servnest.key -out /etc/ssl/certs/servnest.crt
openssl req -subj '/CN=servnest.test' -new -newkey RSA:3072 -days 3650 -nodes -x509 -keyout /etc/ssl/private/servnest.test.key -out /etc/ssl/certs/servnest.test.crt
openssl req -subj '/CN=ht.servnest.test' -new -newkey RSA:3072 -days 3650 -nodes -x509 -keyout /etc/ssl/private/ht.servnest.test.key -out /etc/ssl/certs/ht.servnest.test.crt
openssl req -subj '/CN=*.ht.servnest.test' -new -newkey RSA:3072 -days 3650 -nodes -x509 -keyout /etc/ssl/private/wildcard.ht.servnest.test.key -out /etc/ssl/certs/wildcard.ht.servnest.test.crt

A precise configuration is inside the nginx/ directory. It requires the headers more nginx module.

This configuration listens on [::1]:42443, 127.0.0.1:42443, [::1]:42080 and 127.0.0.1:42080. For a public server, these should be replaced respectively by [::]:443, 0.0.0.0:443, [::]:80 and 0.0.0.0:80. Other addresses (i.e for Onion services and SFTPGo authentication) are not meant to be publicly exposed.

Once this configuration is put in place, replace self-signed certificates by Let's Encrypt certificates:

certbot certonly -d "ht.servnest.example"
certbot certonly -d "servnest.example"

Getting a Let's Encrypt certificate for a wildcard domain requires an ACME DNS challenge. The following command asks to setup a DNS record, this can be done by editing /srv/servnest/reg/servnest.example then reload configuration using knotc zone-reload servnest.example.

certbot certonly --manual -d "*.ht.servnest.example"

This method also requires manual operations for renewal.

The nginx configuration provided above uses the self-signed key pair at the locations set in the openssl command above. Replace those by the ones Certbot told you and reload nginx configuration.

Allow nginx to access certificates:

mkdir -p /etc/letsencrypt/archive/ /etc/letsencrypt/live/
chmod 710 /etc/letsencrypt/archive/ /etc/letsencrypt/live/
chown root:nginx /etc/letsencrypt/archive/ /etc/letsencrypt/live/
/root/certbot-deploy-hook.sh

Apache HTTP Server

Apache in distributions is usually named httpd, apache or apache2. Adapt these instructions as appropriate.

Apache configuration is inside the apache/ directory. It runs Apache inside a chroot, though it is not required by the ServNest design. Some paths may need adaptation according to the distribution used (e.g. modules or logs).

Set up the directory where Apache will be chrooted:

mkdir /srv/servnest/ht
cp -r /install/http-messages /srv/servnest/ht/http-messages
chown -R root:root /srv/servnest/ht
chmod -R u=rX,g=rX,o=rX /srv/servnest/ht

Set up the directory managed by SFTPGo users:

mkdir /srv/servnest/ht/fs
chown -R apache:sftpgo /srv/servnest/ht/fs
chmod -R u=rX,g=rwX,o= /srv/servnest/ht/fs

Set up the directory accessed by Apache and managed by ServNest that maps Web addresses to users directories using links:

mkdir /srv/servnest/ht/uri
mkdir /srv/servnest/ht/uri/ht.servnest.test # Subpath access
chown -R servnest:apache /srv/servnest/ht/uri
chmod -R u=rwX,g=rX,o= /srv/servnest/ht/uri

For Apache to work in a chroot, hardlinking some system dependencies inside the chroot may be needed:

# Display dependencies paths
ldd $(which httpd)

# Create hardlink's parent directory
mkdir -p /srv/servnest/ht/usr/lib

# Hardlink (with a specific example)
ln /usr/lib/libc.so.6 /srv/servnest/ht/usr/lib/libc.so.6

SFTPGo

Install SFTPGo

The script at ../root/sftpgo.sh can be used to build SFTPGo from source. You can use other methods to get SFTPGo builds.

Create a directory for configuration: mkdir /etc/sftpgo

Copy the systemd service: cp /install/sftpgo.service /etc/systemd/system/sftpgo.service

Allow listening on privileged ports: setcap 'cap_net_bind_service=+ep' /usr/local/bin/sftpgo

Configure SFTPGo for ServNest

Generate a key pair using ssh-keygen -f /etc/sftpgo/ed25519 -t ed25519 -N "" -C ""

Compute key pair fingerprints:

fp=($(ssh-keygen -l -f /etc/sftpgo/ed25519))
echo ${fp[1]} > /etc/sftpgo/ed25519.fp
ssh-keygen -lv -f /etc/sftpgo/ed25519 | tail -n +2 > /etc/sftpgo/ed25519.asciiart

Copy the SFTPGo configuration: cp /install/sftpgo.toml /etc/sftpgo/sftpgo.toml. For a public setup, change [[sftpd.bindings]] sections in it to public IPs and port 22. You can optionally set up in /etc/sftpgo/banner.txt a message displayed to users when logging in.

Add user servnest to group sftpgo:

usermod -aG sftpgo servnest

Permissions for /etc/sftpgo:

chown -R sftpgo: /etc/sftpgo
chmod -R u=rX,g=rX,o= /etc/sftpgo
chmod u=r,g=,o= /etc/sftpgo/ed25519

Generate and add SSHFP record for the public SFTP domain:

echo sftp.servnest.test. 86400 SSHFP 4 2 $(cut -d ' ' -f 2 /etc/sftpgo/ed25519.pub | base64 -d | sha256sum | cut -d ' ' -f 1) >> /srv/servnest/reg/servnest.test.zone

ServNest core configuration

Copy the configuration template to the actual configuration file and adapt it according to the ServNest configuration reference:

cp /srv/servnest/core/config.template.ini /srv/servnest/core/config.ini
vim /srv/servnest/core/config.ini