VPS setup on digitalocean
Nov 2, 2022
In this post I will document my setup of an Ubuntu 22.04 VPS at Digital Ocean. I will provide links to resources at digitalocean.com (and elsewhere) that guided the choices I made. Of course, this is just one way to do it. This post is primarily a documentation of the process for myself. The results may, or may not, be helpful to you. So, be sure to read mutiple resources if you are trying this yourself.
Create a droplet
The first step is create a droplet at digitalocean.com Droplet is the name Digital Ocean gives to its VPS. See How to create a droplet at digitalocean.com for a more detailed overview. Some choices I made are:
- New York datacenter
- Ubuntu 22.04 LTS image
- Droplet type: Basic, regular with SSD ($6/mo for 1GB ram, 25GB SSD disk 1000GB transter)
- Chose to connect to droplet with password (for now)
- I enabled improved metric monitoring and alerting (free)
- I gave the droplet a Hostname under Finalize Details and made sure to select the correct project.
Click Create droplet and wait for a minute or so for the droplet to be created-- an IP should appear on the control board.
Intial server setup
The next step is to do some setup, following: Initial Server Setup with Ubuntu 22.04 . Everything is pretty straightforward, but it's nice to follow a guide to make sure that I don't miss anything.
Update the server
It is likely that the droplet will need to be updated. This should be done at the start:
$ sudo apt update
$ sudo apt upgrade
When the updates are complete, reboot the server:
$ sudo reboot
Create a new user
First we create a new user so that we don't have to do everything as root. To do this we ssh to the new droplet using the IP from the control panel (I'll use xxx.xxx.xx.xxx as a stand-in). Of course you'll need to use the password that you gave when creating the droplet:
$ ssh root@xxx.xxx.xx.xxx
To create a new user (I'll use username as a stand-in here) the command is:
$ adduser username
As always, be sure to create strong password and save with a password manager.
Admin privileges
Next we want to give the new user admin privelges so that we can execute
sudo
commands with the account:
$ usermod -aG sudo username
Change the ssh port
The default port for ssh is port 22. This port gets a lot of malicious activity for obvious reasons, so I change my ssh port. This means we have to edit the /etc/ssh/sshd_config file. I will use vim, but nano, vi, etc. will work.
$ vim /etc/ssh/sshd_config
To change the port to YYYY find the line that has
#Port 22
and change it to
Port YYYY
. Finally, restart the ssh
daemon
$ systemctl restart ssh
We can check that the new port is selected using
$ ss -tlpn | grep ssh
It should be clear that ssh is listening on port YYYY.
Setup ssh key
I want to setup ssh key access to the server for my new user account. To do this I will start by generating a new ssh key on my laptop using:
- The rsa algorithm
-t rsa
- 4096 bits
-b 4096
- Specify a filename for the key
-f keyfile
- Specfiy the username and host in the comment
-C "username@xxx.xxx.xx.xxx"
$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/keyfile -C "username@xxx.xxx.xx.xxx"
We can check the keyfile and keyfile.pub files have been created using:
$ ls ~/.ssh/
Now we can copy the public key to the new server (using port YYYY):
$ ssh-copy-id -i ~/.ssh/keyfile.pub -p YYYY username@xxx.xxx.xx.xxx
Note:
If you get an error about too many authentication errors this is apparently caused by having many/(more than one) ssh keys and can be resolved using the following:
$ ssh-copy-id -o IdentitiesOnly=yes -i ~/.ssh/keyfile.pub -p YYYY username@xxx.xxx.xx.xxx
Finally, I will add this identity to my ~/.ssh/config file on my laptop by adding the following entry:
Host my-host-name
HostName xxx.xxx.xxx.xx
Port YYYY
IdentityFile ~/.ssh/keyfile
User username
This will allow me to ssh to the machine without specifying the keyfile, port, etc using the simple command:
$ ssh my-host-name
Disable Root Login
Once access is setup and tested as described above it's a good idea to disable root login on the machine. DigitalOcean has a good overview here: How To Disable Root Login on Ubuntu 20.04 and the process is simple. First, edit the sshd_config with vim (or nano, vi, etc):
$ sudo vim /etc/ssh/sshd_config
Scroll down to find the Authetication section and change the line that says:
PermitRootLogin yes
so that it reads
PermitRootLogin no
Next, we have to restart the sshd daemon using
$ sudo systemctl restart ssh
Finally, you should log out and try to log in using root-- this should now fail.
Setup ufw firewall
Now we setup UFW for some basic protections. This also a good time to make sure all of the above works and we can ssh to the droplet using the ssh key setup above-- this must work before setting up elements of the firewall that will restrict access! Start by logging out of the root account and then ssh to the droplet as shown above:
$ ssh my-host-name
A quick test to make sure that ufw is inactive should produce:
$ sudo ufw status
Status: inactive
Next, let's start with defaults:
- Allow all outgoing
- Deny all incoming
$ sudo ufw default allow outgoing
$ sudo ufw default deny incoming
We can make sure that IPv6 is enabled using (it should be on our Ubuntu 22.04 server):
$ grep IPV6 /etc/default/ufw
IPV6=yes
Next, we enable incoming ssh on port YYYY-- we won't be able to access the server after enabling the firewall if we don't do this!
$ sudo ufw allow YYYY/tcp
Finally, let's enable ufw and check the status:
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
$ sudo ufw status
Status: active
To Action From
-- ------ ----
YYYY/tcp ALLOW Anywhere
YYYY/tcp (v6) ALLOW Anywhere (v6)
Notice the warning that ssh connections might be disrupted. You have to type
y
and enter
to enable.
Install nginx
Next up I will install the nginx web server. Following How To Install Nginx on Ubuntu 22.04 , this is done with a simple:
$ sudo apt update
$ sudo apt install nginx
With nginx installed it will now show on the ufw list:
$ sudo ufw app list
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
For now, I will allow 'Nginx HTTP' to test my IP using a browser:
$ sudo ufw allow 'Nginx HTTP'
$ sudo ufw status
Status: active
To Action From
-- ------ ----
YYYY/tcp ALLOW Anywhere
Nginx HTTP ALLOW Anywhere
YYYY/tcp (v6) ALLOW Anywhere (v6)
Nginx HTTP (v6) ALLOW Anywhere (v6)
nginx has a default/example ready to go. At this point we can type/paste the IP address of our droplet, xxx.xxx.xx.xxx, into a browser and see the Welcome to nginx! page.
Useful nginx commands
While we are here, it's useful to document some basic commands for nginx for future reference:
$ sudo systemctl stop nginx
$ sudo systemctl start nginx
$ sudo systemctl restart nginx
There is also a reload
command, but I
typically restart:
$ sudo systemctl reload nginx
Finally, nginx is setup to start when the server reboots. This is useful when updating the server and a reboot is needed. This behavior can be started or stopped using:
$ sudo systemctl enable nginx
$ sudo systemctl disable nginx
We can always check on the status of nginx using
$ sudo systemctl status nginx
Setting up server blocks
This section is for demonstration purposes and will only work if you have a domain name purchased and DNS setup. As a placeholder I'll use testsite, but for this site I would substitute chrisstrelioff.ws. The following steps would be sufficient to have http setup for testsite. I'll go over securing the site with https below.
To start, we create the need directories and make sure ownership and permissions are set:
$ sudo mkdir -p /var/www/testsite/html
$ sudo chown -R $USER:$USER /var/www/testsite/html
$ sudo chmod -R 755 /var/www/testsite
Next, we create a basic index.html file to display using vim
$ sudo vim /var/www/testsite/html/index.html
Following How To Install Nginx on Ubuntu 22.04 , the file contents are
<html>
<head>
<title>Welcome to testsite!</title>
</head>
<body>
<h1>Success! The <u>testsite</u> server block is working!</h1>
</body>
</html>
Next we create a configuration file for testsite
$ sudo vim /etc/nginx/sites-available/testsite
with the contents
server {
listen 80;
listen [::]:80;
root /var/www/testsite/html;
index index.html index.htm index.nginx-debian.html;
server_name testsite www.testsite;
location / {
try_files $uri $uri/ =404;
}
}
Finally, to make testsite active (this won't work here for reasons discussed above) the file we created in /etc/nginx/sites-available/ has to have a symbolic link to the /etc/nginx/sites-enabled/ directory. We do this with
$ sudo ln -s /etc/nginx/sites-available/testsite /etc/nginx/sites-enabled/
There are now two site enables on the VPS
- The default site-- we see this when using the IP
- The testsite-- we would see this if we had the domain name and DNS setup
$ ll /etc/nginx/sites-enabled/
total 8
drwxr-xr-x 2 root root 4096 Nov 10 21:02 ./
drwxr-xr-x 8 root root 4096 Nov 2 20:09 ../
lrwxrwxrwx 1 root root 34 Nov 2 20:09 default -> /etc/nginx/sites-available/default
lrwxrwxrwx 1 root root 35 Nov 10 21:02 testsite -> /etc/nginx/sites-available/testsite
The arrows indicate that there is a symbolic link to the files shown. As you can see, this single nginx server can host multiple sites at the same time as long as there are sufficient computing resources available.
Securing nginx with https
A final step in this setup is to secure the site, following How To Secure Nginx with Let's Encrypt on Ubuntu 22.04 .
Installing Certbot
As suggested in the post linked above, install certbot with snap. Apparently snap is available from the get-go, so we only need to make sure that snapd core is updated:
$ sudo snap install core
[sudo] password for username:
core 16-2.57.2 from Canonical✓ installed
$ sudo snap refresh core
snap "core" has no updates available
This is a fresh install of Ubuntu 22.04 on the droplet, so I don't have to worry about removing old versions of certbot. The install command is:
$ sudo snap install --classic certbot
certbot 1.32.0 from Certbot Project (certbot-eff✓) installed
Finally, as suggest in the post, we create a symbolic link for certbot to run from /usr/bin/:
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Now, certbot can be run by typing the name. For example:
$ certbot --version
certbot 1.32.0
Check nginx's configuration
In order to create an SSL certificate, the nginx server blocks have to be setup as discussed above. In particular, testsite and its www counterpart need to be listed in the server_name line. This can be checked using:
$ more /etc/nginx/sites-available/testsite | grep server_name
server_name testsite www.testsite;
If you don't get something similar, with testsite replaced with your domain name the server block setup should be checked carefully-- see above, as well as the links to original source posts!
Update ufw to allow https
Next up, the firewall needs to updated to allow for https traffic. We did not allow that above, so this has to be changed. This is accomplished by enabling 'Nginx Full' and disabling 'Nginx HTTP':
$ sudo ufw allow 'Nginx Full'
Rule added
Rule added (v6)
$ sudo ufw delete allow 'Nginx HTTP'
Rule deleted
Rule deleted (v6)
Changes can be confirmed by checking the status:
$ sudo ufw status
Status: active
To Action From
-- ------ ----
YYYY/tcp ALLOW Anywhere
Nginx Full ALLOW Anywhere
YYYY/tcp (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
The results should look something like this-- there are also entries for ssh that we setup above.
Get an SSL certificate
Okay, we should be ready to generate our SSL certificate using the following command (again, change testsite with you domain name):
$ sudo certbot --nginx -d testsite -d www.testsite
If everthing goes well you are asked a set of questions:
- Asked to provide an email
- Asked to agree with Terms of Service here
- Asked if you want emails from EFF (Electronic Frontire Foundation) - you should say yes :)
If everthing goes well, your account should be registed and a certificate/key created in /etc/letsencrypt/live/testsite/
If you start a browser and go to testsite it should now automatically redirect to https. You can test the strength of the setup at the SSL Labs Server Test. As suggested on the digitalocean post, How To Secure Nginx with Let's Encrypt on Ubuntu 22.04 . the results are an A grade!
Auto-renewal for Certbot
The certificates that are generated only last for 90 days. The certbot install is supposed to configure automatic renewall. We should check:
$ sudo systemctl status snap.certbot.renew.service
[sudo] password for username:
○ snap.certbot.renew.service - Service for snap application certbot.renew
Loaded: loaded (/etc/systemd/system/snap.certbot.renew.service; static)
Active: inactive (dead)
TriggeredBy: ● snap.certbot.renew.timer
This response is a little cryptic-- it's hard to know what it means. We can try a test/dry-run and should get something like the following if everthing is good to go:
$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/testsite.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for testsite and www.testsite
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/testsite/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Wrapping Up
That's it for this post. We went from nothing to a VPS running Ubuntu 22.04, nginx, and https working! That's enough for one day...