An opinionated setup process for "all-things" Debian VPS configuration from scratch.
1: Basic server configuration for all instances.
2: Server hardening for all instances.
3: Web server configurations [ Apache / Nginx / Node + PM2 ]
4: Server maintenance
5: Data backups
6: Bootstraps
Basic Linux configurations to use in all VPS instances.
$ apt update && apt upgrade
$ hostnamectl set-hostname "hostname"
$ echo "hostname" > /etc/hostname
$ hostname -F /etc/hostname
$ dpkg-reconfigure tzdata
$ date
$ adduser "username"
$ apt install sudo
$ usermod -a -G sudo "username"
A modern, easy-going, and powerful shell.
$ sudo apt install fish
$ sudo chsh -s /usr/bin/fish
$ sudo shutdown -r now
Basic hardening configurations to use in all VPS instances.
On the server:
$ mkdir -p ~/.ssh/ && sudo chmod -R 700 ~/.ssh/
$ sudo chmod 700 -R ~/.ssh && chmod 600 ~/.ssh/authorized_keys
On local machine:
$ scp ~/.ssh/id_rsa.pub username@vpsipaddress:~/.ssh/authorized_keys
File: /etc/ssh/sshd_config
# Authentication reforce
PermitRootLogin no
PasswordAuthentication no
# Listen on only on IPv4
AddressFamily inet
Restart SSH
$ sudo systemctl restart sshd
Simple intrusion prevention software.
$ apt install fail2ban
Configure:
$ cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local
$ cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
File /etc/fail2ban/jail.local:
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 600
findtime = 600
maxretry = 3
backend = auto
usedns = warn
destemail = root@localhost
sendername = Fail2Ban
banaction = iptables-multiport
mta = sendmail
protocol = tcp
chain = INPUT
action_ = %(banaction)...
action_mw = %(banaction)...
protocol="%(protocol)s"...
action_mwl = %(banaction)s...
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 4
$ sudo ss -atpu
$ sudo apt purge "package_name"
Rkhunter and chkrootkit:
$ sudo apt install rkhunter
$ sudo rkhunter --propupd
$ sudo rkhunter --check
$ sudo apt install chkrootkit
Always iptables: Minimal configuration; Easygoing; Effective.
$ sudo iptables -L
$ sudo apt install iptables-persistent
$ sudo nano /etc/iptables/rules.v4
iptables file [ download here ]:
*filter
# Allow all outgoing, but drop incoming and forwarding packets by default
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# Custom per-protocol chains
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]
# Acceptable UDP traffic
# Acceptable TCP traffic
-A TCP -p tcp --dport 80 -j ACCEPT
-A TCP -p tcp --dport 443 -j ACCEPT
-A TCP -p tcp --dport 22 -j ACCEPT
# Acceptable ICMP traffic
# Boilerplate acceptance policy
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
# Drop invalid packets
-A INPUT -m conntrack --ctstate INVALID -j DROP
# Pass traffic to protocol-specific chains
## Only allow new connections (established and related should already be handled)
## For TCP, additionally only allow new SYN packets since that is the only valid
## method for establishing a new TCP connection
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
# Reject anything that's fallen through to this point
## Try to be protocol-specific w/ rejection message
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
# Commit the changes
COMMIT
*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
$ sudo iptables-restore -t /etc/iptables/rules.v4
$ sudo nano /etc/iptables/rules.v6
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
*raw
:PREROUTING DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
*nat
:PREROUTING DROP [0:0]
:INPUT DROP [0:0]
:OUTPUT DROP [0:0]
:POSTROUTING DROP [0:0]
COMMIT
*security
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
*mangle
:PREROUTING DROP [0:0]
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
:POSTROUTING DROP [0:0]
COMMIT
$ sudo ip6tables-restore -t /etc/iptables/rules.v6
$ sudo service netfilter-persistent reload
$ sudo iptables -S
$ sudo ip6tables -S
Lynis to perform full system audits.
$ sudo apt install lynis
To monitor active SSH connections.
$ sudo apt install whowatch
Multiple configurations for regular web server needs.
1: Apache with Virtual Host to host multiple websites
2: Nginx with Server Blocks to host multiple websites
3: NodeJS and PM2 to host multiple Nuxt instances
4: Secure web traffic with Let's Encrypt's Certbot
$ sudo apt install apache2
$ sudo chmod -R 755 /var/www
Enable the ssl module
$ sudo a2enmod ssl
Enable the proxy module
$ sudo a2enmod proxy
Enable the http2 module
$ sudo a2enmod http2
Restart Apache.
$ sudo systemctl restart apache2
Apache folder structure.
$ mkdir -p /var/www/domain.com/public_html/
$ touch /var/www/domain.com/public_html/index.html
Apache config for http:
$ touch /etc/apache2/sites-available/domain.com.conf
<VirtualHost *:80>
ServerAdmin webmaster@domain.com
ServerName domain.com
ServerAlias www.domain.com
DocumentRoot /var/www/domain.com/public_html/
ErrorLog /var/www/domain.com/logs/error.log
CustomLog /var/www/domain.com/logs/access.log combined
Redirect permanent / https://domain.com/
</VirtualHost>
Apache config for https:
$ touch /etc/apache2/sites-available/domain.com-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin webmaster@domain.com
ServerName domain.com
ServerAlias www.domain.com
DocumentRoot /var/www/domain.com/public_html/
ErrorLog /var/www/domain.com/logs/error.log
CustomLog /var/www/domain.com/logs/access.log combined
SSLCertificateFile /etc/letsencrypt/live/domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
SSLCACertificateFile /etc/letsencrypt/live/domain.com/cert.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Map the domain.
$ sudo a2ensite domain.com.conf
Restart the Apache service to register the changes.
$ sudo systemctl restart apache2
$ sudo apt install nginx
$ sudo chmod -R 755 /var/www
Nginx folder structure.
$ sudo mkdir -p /var/www/your_domain/html
$ sudo chown -R $USER:$USER /var/www/your_domain/html
$ sudo chmod -R 755 /var/www/your_domain
$ sudo chmod -R 755 /var/www/your_domain
sample index.html
$ nano /var/www/your_domain/html/index.html
your_domain config default config file
$ sudo nano /etc/nginx/sites-available/your_domain
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name domain.com www.domain.com;
root /var/www/domain.com;
index index.html;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "
default-src 'none';
script-src 'self' 'strict-dynamic' 'nonce-RANDOM';
style-src 'self';
img-src 'self' data:;
object-src 'none';
base-uri 'none';
form-action 'self';
frame-ancestors 'self';
" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Permissions-Policy "geolocation=(), microphone=()" always;
# Hide Nginx version number
server_tokens off;
location / {
try_files $uri $uri/ =404;
}
gzip on;
gzip_comp_level 3;
gzip_types text/plain text/css application/javascript image/*;
}
enable server block
$ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
safeguard for hash bucket memory
$ sudo nano /etc/nginx/nginx.conf
...
http {
...
server_names_hash_bucket_size 64;
...
}
...
nginx verification
$ sudo nginx -t
$ sudo systemctl restart nginx
$ sudo apt install nodejs
$ sudo apt install npm
$ sudo npm install pm2 -g
$ sudo pm2 list
$ sudo pm2 monit
Configuring Apache to Reserve Proxy to PM2:
<VirtualHost *:80>
ServerAdmin webmaster@domain.com
ServerName domain.com
ServerAlias www.domain.com
DocumentRoot /var/www/domain.com/public_html
ErrorLog /var/www/domain.com/logs/error.log
CustomLog /var/www/domain.com/logs/access.log combined
ProxyPreserveHost On
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
Redirect permanent / https://domain.com/
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin webmaster@domain.com
ServerName domain.com
ServerAlias www.domain.com
DocumentRoot /var/www/domain.com/public_html
ErrorLog /var/www/domain.com/logs/error.log
CustomLog /var/www/domain.com/logs/access.log combined
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
SSLCertificateFile /etc/letsencrypt/live/domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
SSLCACertificateFile /etc/letsencrypt/live/domain.com/cert.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
$ sudo apt install certbot
Request a certificate for Apache:
$ sudo certbot --apache -d domain.com -d www.domain.com
Request a certificate for Nginx:
$ sudo certbot --nginx -d domain.com -d www.domain.com
Certificate automated renewals:
$ sudo certbot renew --dry-run
Semi-regular healthy maintenance tasks.
$ sudo lynis show options
$ sudo lynis audit system
$ sudo rkhunter -C
$ sudo rkhunter > ~/audits/rkhunter-audit-results.txt
$ sudo chkrootkit > ~/audits/chkrootkit-audit-results.txt
$ sudo whowatch
Simple processes to backup all-things VPS data:
Regular compressed backups:
$ tar pczvf ~/backup/vps-backup-home.tar.gz ~/var/home
$ tar pczvf ~/backup/vps-backup-web.tar.gz ~/var/www
$ tar pczvf ~/backup/vps-backup-logs.tar.gz ~/var/log
$ tar pczvf ~/backup/vps-backup-apache.tar.gz ~/etc/apache2
$ tar pczvf ~/backup/vps-backup-nginx.tar.gz ~/etc/nginx
$ tar pczvf ~/backup/vps-backup-letsencrypt-certificates.tar.gz ~/etc/letsencrypt
$ tar pczvf ~/backup/vps-backup-security-audits.tar.gz ~/var/home/audits
Rsync from local machine:
$ rsync -ahvz username@vpsipaddress:/path/to/source/backup /path/to/local/backup/
A bunch of opinionated and hardened files for multiple software configs: