Guide: Ubuntu Server Administration - dsriseah/ursys GitHub Wiki

My testing instance is a Digital Ocean 4GB Ubuntu Droplet. This is an unmanaged bare Ubuntu install, so I have to do a bunch of stuff to make it reachable by the outside world. Setting up this access is done from the Digital Ocean control panel via their website, as this provides root login via their console tool.

Note: I've already executed these commands on the freshly created server:

sudo apt update
sudo apt upgrade
adduser dsri
usermod -aG sudo dsri

which makes sure my Ubuntu instance is up-to-date, and I have a user named dsri that is part of the superuser group so I can use sudo to execute privileged commands.

1. Making the Droplet Reachable

Do this in the DO Control Panel under Networking, and point subdomains to specific droplets. For example, I've pointed the domain to my Ubuntu droplet using the DO Control Panel. The domain's nameservers are set to, etc so this works.

At minimum, I need to setup various services. So far, we only have SSH installed and a superuser dsri created. These following steps are roughly in the order that makes sense, building on previous steps.

2. Setting up NGINX Web Server

From this tutorial, modified for use from the Digital Ocean root console.

apt install nginx
ufw app list            # lists all ufw apps to configure
ufw allow 'Nginx Full'  # updates firewall rules
ufw allow 'OpenSSH'     # make sure ssh is allowed too
ufw status              # shows that ufw is inactive

IMPORTANT: ufw is INACTIVE because we want to double-check that everything is working before turning on the firewall.

Next, check that nginx daemon is running, and then retrieve the public address of the droplet

systemctl status nginx         # shows me it's running
curl -4          # shows me my public IPv4 address (e.g.
# browse to ip address in Chrome or something to see 'Welcome to nginx!' page


Here's the list of systemctl commands: stop start restart reload disable enable

Here the host files will be in 'ursys_dsri_xyz/html', with permissions set correctly. Make sure who are logged in at the superuser, not root (use whoami to see). Also not that chown is on /html and chmod is not below!

mkdir -p /var/www/ursys_dsri_xyz/html
chown -R dsri:dsri /var/www/ursys_dsri_xyz/html
chmod -R 755 /var/www/ursys_dsri_xyz

Create a default index file. It won't be visible yet...

nano /var/www/ursys_dsri_xyz/html/index.html 

Now we have to also set up a nginx server block for the specific host. First, set up where the files should be served from. From Step 5 of the tutorial:

cd /etc/nginx/sites-available
sudo nano ursys_dsri_xyz    # create new file

Enter into the file:

server {
    listen 80;
    listen [::]:80;

    root /var/www/ursys_dsri_xyz/html;
    index index.html index.htm;


    location / {
        try_files $uri $uri/ =404;

Quit, then...

ln -s /etc/nginx/sites-available/ursys_dsri_xyz /etc/nginx/sites-enabled/
nano /etc/nginx/nginx.conf   # uncomment server_names_hash_bucket_size 64
nginx -t   # test rules

If everything looks good:

sudo systemctl restart nginx   

Browse to the website and you should see that your index file being served for the domain. If you go directly to the IP address, you should see the default nginx greeting that's stored in /var/www (see the nginx conf default server)

3. Setting up HTTPS with SSL Certificate from Let's Encrypt

There's another DO tutorial on setting up nginx with let's encrypt. Basically make sure these preequisites are already set:

  • sudo-enables non-root user
  • registered domain name
  • dns record set up for server
  • nginx installed
  • server block for domain installed
  • check server block domain name
  • check ufw allow 'Nginx Full'
  • check ufw allow 'OpenSSH' (just to make sure we can still login)

We've already done all that, so next we just install the Let's Encrypt CertBot that handles the certification acquisition and renewal proces.

Still as root via the DO Control Panel, run these two lines:

apt install certbot python3-certbot-nginx
certbot --nginx -v -d * -d  # wildcard subdomain plus main domain

After following the instructions and seeing confirmation that the certificate has been installed in nginx config, test that the certificate will autorenew via certbot

systemctl status certbot.timer

Then test that it would work with

certbot renew --dry-run

Hooray! Incidentally, the serverblock definition has now being annotated with certbot additions that makes this all work. Try more /etc/nginx/sites-available/ursys_dsri_xyz to see what's been added.


Wildcard certificates don't work on Digital Ocean with autorenewal, so I have to install some kind of "hook script" as described here in a few months when the current cert expires.

4. Setting up SSH Access Key Pairs for User

So far we've been relying on Digital Ocean's console from the control panel, but we'd like to SSH from our own terminal on the local dev machine. This involves creating an ssh key pair on the machine that I want to login from, and then copying the public part of the key pair to the DO Droplet.

Here's the instructions from Setting up SSH Keys from DO, on which this is based:

First generate a key pair if you don't already have one. On your Mac:

ssh-keygen -t ed25519  # generate key pair identity

Make sure you use a name like do-nyc1.ed25519 for the pair, which will live in your ~/.ssh directory. Don't overwrite the existing id_rsa identitiy!!! which is the default.

Next, you have to add a new ssh identity to your ~/.ssh/config file, somethiing like this:

Host do-nyc1
  User dsri
  PubkeyAuthentication yes
  IdentitiesOnly yes
  IdentityFile ~/.ssh/do_nyc1_ed25519
  UseKeychain yes
  AddKeysToAgent yes


Securely back-up your keys in case you have to change computers or restore the operating system. If you lose the two key files, you will lose access to any systems you used with with!

After updating the config you'll reload the configuration (this is Apple specific):

ssh-add -K ~/.ssh/keyfile   # this is an Apple thing
ssh-add -D                  # reload ssh agent with updated config

On the server, you'll want to append the contents of the Public key to the server's ~/dsri/.ssh/authorized_keys file. This public key ends with .pub, so in this example it would be in the ~/.ssh/ file.

To upload the public key:

ssh-copy-id -i ~/.ssh/publickey dsri@host


in the .ssh/config file, the Host field is what matches as user@host, not HostName. For example, if you had two different user names on the same server, you would define two entries with Host server-alice HostNme and Host server-bob HostName and login with ssh with ssh alice@server-alice

After you do that, you should be able to connect to the host with

ssh dsri@host

Where host is one of the Host fields in your .ssh/config file.


If there is an issue connecting with the server, it may be because an obsolete version of SHA1 is not allowed by MacOS. The workaround is not to use the default ssh-keygen command, but to use a different cipher system -t ed25519 as shown above. See this superuser comment

TROUBLESHOOTING - If you're having trouble pushing to Github, check out Guide: Github Identities.

5. Configuring VSCode for Remote Editing

Using DO Guide to setting up VSCode for Remote-SSH...


  • open vscode
  • make sure "Remote-SSH" extension is installed
  • cmd-shift-p "Remote-SSH: Connect to Host"

You'll be presented with a list of hosts that are pulled from your .ssh/config file. You should be able to just select it.

Now, you can open the folder! If there's a workspace select that!

Appendix: Enabling the Firewall

TBD or moved to Guide: Securing URSYS

⚠️ ** Fallback** ⚠️