Secure your VPS - The easy way
Go get your VPS
Want to deploy your apps yourself but don't know where to start? I've been there...
When you host your app on a remote machine, aka VPS (Virtual Private Server), you are responsible for what happens on it so security is a big concern.
It often makes people postpone the beginning of their self-hosting journey and sometimes even give up on it completely.
In this tutorial, you will see how to secure your VPS server with easy steps.
First, choose your favorite provider (Hetzner, OVH, Scaleway, Digital Ocean, AWS, etc.). Personally recommend Hetzner, great value for the price (Not sponsored BTW)
Then you can create a new VPS instance with your desired OS (Ubuntu LTS is recommended for beginners).
When you set up your vps, the provider will ask for an ssh key so that you can connect to your server securely.
If you don't have one yet, you can generate it with:
# Recommended
ssh-keygen -t ed25519 -C "[email protected]"
# If your computer does not support ed25519, use rsa
ssh-keygen -t rsa -b 4096 -C "[email protected]"
You can set a passphrase for added security at the cost of convenience as you will have to enter your password each time you connect to your server.
If you do not change the default location, your keys will be generated in ~/.ssh
You will have these files inside: ~/.ssh/id_ed25519 and ~/.ssh/id_ed25519.pub (or ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub for rsa).
.pub means that's the public key, the other file is the private key that you should never share with anyone.
Now you can add your public ssh key to your vps provider admin panel.
If you followed all these steps, you should be able to connect to your server with:
ssh root@your_server_ip
Update the server
Your server will probably not be up to date when you first connect so the first thing to run is:
sudo apt update
sudo apt upgrade
Then modify the root password:
passwd root
Create a new user with sudo privileges
adduser your_username
apt install sudo
usermod -aG root,sudo,adm your_username
Now edit the sshd_config file to disable root login and only allow your new user to connect
sudo vi /etc/ssh/sshd_config
# Do not permit root user to connect via ssh
PermitRootLogin no
# Make sure only your new user can connect to ssh
AllowUsers your_username
# Optional
# Default ssh port is 22
Port 22
Restart ssh to apply the changes:
service ssh restart
If you changed the ssh port, you must specify it when you connect to your server:
ssh your_username@your_server_ip -p your_new-port
You can keep ssh port to 22 but if you want to change it, choose a port between 1024 and 65535 to avoid conflicts with well known ports.
This will avoid malicious bots scanning the default ssh port.
Don't worry, you will add new layers of security so you can keep the port 22 for ssh if you find it simpler.
Now test that you can connect with the new user and have sudo available:
sudo ls -l ./
Firewall
Now that ssh access is secured, you need to set up a firewall to restrict incoming traffic only to the services you want to expose.
sudo apt install iptables
Time to create the firewall rules. You can use this basic template.
#localhost
sudo iptables -A INPUT -i lo -j ACCEPT
#web
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
#ssh - WARNING Change 22 to the port you've chosen if you changed it
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
#dns
sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT
#git
sudo iptables -A INPUT -p tcp --dport 9418 -j ACCEPT
# smtp/imap/sieve are for sending emails
# Useful if you want to send yourself daily or weekly logs of your vps
# Ignore if you don't need them
#smtp
sudo iptables -A INPUT -p tcp --dport 25 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 587 -j ACCEPT
#imap/sieve
sudo iptables -A INPUT -p tcp --dport 993 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 4190 -j ACCEPT
# Stop all traffic that is not explicitly allowed
sudo iptables -A INPUT -j DROP
# Save config for reboots
sudo -s iptables-save -c
If you want to make sure everything works, you can see applied firewall rules with:
sudo iptables -L
Your own jail with Fail2ban
Fail2Ban is a fantastic tool to have on any server exposed to the internet. The penitentiary for malicious users.
It will monitor your logs and ban IPs that show malicious signs, such as too many password failures.
sudo apt install fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo vi /etc/fail2ban/jail.local
Example /etc/fail2ban/jail.local
...
# Ban time in seconds
bantime = 600
# Range of logs surveillance time
findtime = 600
# Max retries before ban
maxretry = 3
# Email to send notifications
destemail = [email protected]
# Sender name for email notifications
sendername = Fail2ban
...
sudo vi /etc/fail2ban/jail.d/custom.conf
Configure what Fail2ban will monitor. You can use this template and remove unused services.
- Example
/etc/fail2ban/jail.d/custom.conf
# Default jail settings
[sshd]
enabled = true
[sshd-ddos]
enabled = true
[postfix]
enabled = true
[dovecot]
enabled = true
[sieve]
enabled = true
# Longer bans for bots that attack repeatedly if enabled
[recidive]
enabled = true
Restart Fail2ban to apply the changes:
sudo systemctl restart fail2ban
sudo service fail2ban restart
# Run this to make sure everything works
sudo fail2ban-client status
Optional: If you want to receive email notifications, you need to configure your email in the "dest" property of these files:
/etc/fail2ban/action.d/send-mail-common.conf/etc/fail2ban/action.d/mail.conf/etc/fail2ban/action.d/mail-whois.conf
Run security updates automatically
To get security updates automatically, you will need the help of a cronjob.
Install cron-apt
sudo apt install cron-apt
#Then setup security updates
sudo vi /etc/cron-apt/config
- Example
/etc/cron-apt/config
APTCOMMAND=/usr/bin/apt-get
OPTIONS="-o quiet=1 -o Dir::Etc::SourceList=/etc/apt/sources.list.d/ubuntu.sources"
MAILTO="[email protected]"
MAILON="upgrade"
Now cron-apt will check for new security updates and install them. You will receive an email report if you configure the MAILTO property.
It checks for updates at 4am every day by default. You can change that by editing /etc/cron.d/cron-apt.
Take a step back and relax
Congratulations! Your VPS server is ready to use.
You have secured ssh access, set up a firewall, protected your server from brute force attacks with Fail2ban, and automated security updates.
You can now deploy your applications with more confidence.
Optional: Setup smtp to send emails
Your vps provider might have restrictions on sending emails directly from your server to avoid spam.
This means port 25 might be blocked for outgoing connections.
You can send a message to your provider to lift this restriction but a simpler solution is to use an external SMTP relay like Gmail.
If you don't have postfix installed yet, do it now:
sudo apt install postfix
Edit /etc/postfix/main.cf and add or modify these lines:
relayhost = [smtp.gmail.com]:587
smtp_use_tls = yes
smtp_tls_security_level = encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_tls_security_options = noanonymous
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
Make sure relayhost has square brackets — this tells Postfix not to do MX lookups.
Setup your smtp credentials
The simple way is to use your Gmail account.
Do not use your normal Gmail password!
You must use a Google App Password (requires 2FA on your account).
Generate it here: https://myaccount.google.com/apppasswords
Google generates 16-character passwords that you can use in the sasl_passwd file.
If your password has spaces, write the password without them.
Create the password file:
sudo vi /etc/postfix/sasl_passwd
Your file should look like this:
[smtp.gmail.com]:587 [email protected]:your_app_password
Secure and hash the file
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd
It will create /etc/postfix/sasl_passwd.db.
Restart Postfix to apply the changes
sudo systemctl restart postfix
You can test it by sending an email from the command line:
`echo "Test mail from my secured VPS" | mail -s "SMTP relay test" [email protected]
If you check /var/log/mail.log for output, you should see something like:
status=sent (250 2.0.0 OK ...)
Optional: Automated log reports
If you want to receive automated log reports of your server by mail, you can use logwatch. Takes way less time than checking your server manually.
sudo apt install logwatch
sudo cp /usr/share/logwatch/default.conf/logwatch.conf /etc/logwatch/conf/logwatch.conf
sudo vi /etc/logwatch/conf/logwatch.conf
- Example
/etc/logwatch/conf/logwatch.conf
# Receive your reports in html for a better reading experience
Format = html
# Email to send the reports to
MailTo = [email protected]
# Level of detail
Detail = Med
You can generate a report right now to make sure everything is working:
sudo logwatch --mailto [email protected] --output html
Optional: If you want weekly reports instead of daily, you can change the range of logs analyzed by logwatch.
Update Range in logwatch.conf
Range = between -7 days and -1 days
Then move the cronjob to weekly:
sudo mv /etc/cron.daily/00logwatch /etc/cron.weekly/
