Building a LEMP stack for WordPress on Ubuntu 22.04 LTS

Part 2 L: Setting up your Ubuntu 22.04 LTS server

DigitalOcean Initial Server Setup guide

In the following steps I’m working through those outlined in DigitalOcean’s tutorial Initial Server Setup with Ubuntu 22.04.[1] My commentary covers the actions outlined in DO’s setup instructions with my observations on the process.

Connecting to a VPS via SSH

The Secure Shell interface seems familiar to those of us who remember using command-line interface (CLI) systems like Microsoft DOS on PCs or earlier operating systems like BBC BASIC. SSH entails entering commands next to a prompt in an otherwise blank window. On MacOS and Linux machines, you do this using the built-in Terminal utility, while on Windows you’ll work from the Command Prompt.

On MacOS and Linux, locate Terminal with a system search and launch it. On Windows, search for ‘Command Prompt’ and launch the app. To connect to the server, type the following command substituting your_public_IP with your Droplet’s IP address shown on your DO project dashboard:

ssh root@your_public_IP

I’ve pointed my fully-qualified domain name timmassey.website at my Droplet’s public IP, meaning that I can connect to the VPS using ssh root@timmassey.website instead of the root user at the public IP.

The command will return a message warning about connecting to the host because its ‘authenticity can't be established’:

Initial login to DigitalOcean Droplet on MacOS Terminal
Initial login to DigitalOcean Droplet on MacOS Terminal

It’s safe to confirm the connection by typing yes and hitting return. Your computer warns you that it has added the server to its list of known hosts (it will recognise the server as a trusted connection in future) and asks for your root password. Enter the password you set when creating your Droplet — you’ll notice that the password cursor doesn’t move as usual as you type. Press the return key when you’re done and the system shows the Ubuntu 22.04 LTS login text.

Ubuntu 22.04 LTS server first SSH login text
Ubuntu 22.04 LTS server first SSH login text

The server shows the root@your_server_name prompt. Because I named my VPS timmassey.website, the prompt is root@timmassey:~# — the tilde character (~) after the colon shows that the server session is logged into the home directory, and the hash (#) shows that I am logged in as the root user (also indicated by the first part of the prompt).

Some basic server maintenance

The login text in the above screenshot shows that ‘4 updates can be applied immediately’ to Ubuntu 22.04 LTS, and there is a ‘*** System restart required ***’. This is because the distribution has been updated since the version DigitalOcean deployed as its installation image. It’s necessary to update the software regularly when we have the server up and running, and this is a good place to introduce some basic housekeeping commands to help keep things in good order.

Enter the following whenever you see that updates are available — this is particularly important if they are security updates. (Note that, after we set up a non-root user below, we’ll need to enter ‘sudo’ before these commands, but more about that later…)

The first thing to do here is to update the repository lists so that our server has the latest information on the updates available from Ubuntu. Enter this at the hash prompt:

apt-get update

The system scrolls rapidly through fetching the updates available from DigitalOcean’s mirror repositories.

Now install the updates with:

apt-get -y dist-upgrade

It takes a moment or two for the upgrades to flash past until the cursor arrives back at the hash prompt. If the installer shows you package configuration options just accept the default options to continue with a vanilla installation.

Next, a couple of commands to tidy up. These are:

apt autoremove

If the system asks if you want to continue with the removal of packages, type Y to do so. When this process is complete, enter:

apt autoclean

apt autoremove purges the server of superseded files and apt autoclean checks that the directory structure is in order.

The remaining outstanding bit of housekeeping is to restart the server with a straightforward:

reboot

This closes the SSH connection with the server and returns you to the system prompt of your local machine. Wait a few moments while the server restarts before re-establishing the connection with:

ssh root@your_public_IP

The update and restart prompts will have gone from the login text.

We now have a foundation on which to build the stack. Before putting the web server software in place, though, there are a few steps to take to secure the virtual machine.

Essential server security setup

Creating a non-root user

The first login to a newly-minted VPS is necessarily as the root user. root is the main administrative identity for Linux-based operating systems and it has full operating rights on the server with the capacity to create, add, remove, and update all files and directories. This is a security risk because anyone logging in as root has full control of the server. There’s also the risk that a legitimate operator working in root will use damaging commands by mistake. For these reasons, it’s standard practice to create a non-root user with root privileges for general use. As I’ll show, the system challenges non-root users when they use commands that require root privileges to help prevent unauthorised or unintentional actions.

Having logged into the server as root, the way to create a new user is by issuing the following command — I’m using lempstack as a username here, but you can pick a username to suit:

adduser lempstack

The server creates directories associated with your new username and then asks you for a new password. Visit your favourite online secure password generator, create a new one, make a careful note of it, then copy it at the server’s password prompt and re-enter it to confirm it. The server now asks for your full name and some contact details. This information might be helpful if you’re setting up the server for use by a number of operators within an organisation, but it’s not essential to the setup — you can just hit return to leave each field blank.

Bestowing superuser status

We’ve now created a new user account, but this doesn’t yet have root privileges. The way to grant them is by adding the user to the ‘sudo’ group. sudo is a Linux command[2] — a contraction of ‘superuser do’ — that (as we’ll see later) users with root privileges enter before typing commands that require that level of access.

Add your new user to the sudo group with the following command (again my example username is lempstack, and you need to replace this with the username you chose):

usermod -aG sudo lempstack

Server responses

The operating system is quite surly and often won’t give you any feedback after executing a command — it just does it. The above command, for example, will just return you to the root system prompt (#) after adding the new user to the sudo group, but it has done the job despite the lack of response. Often little response from the server is a good sign.

Enabling the firewall

Ubuntu’s built-in firewall is inactive by default and the next step is to configure it so that it allows approved contact with the server. The work we’re doing here is via OpenSSH, so it’s important that the server accepts contact through this app otherwise it will lock us out.

To find out which apps the firewall will allow, enter:

ufw app list

The server responds with:

Available applications:
  OpenSSH

OpenSSH is the lone application installed so far on our fresh instance of Ubuntu 22.04 LTS, which is why there are no other apps in this list. Activate OpenSSH by entering:

ufw allow OpenSSH

The server comes back with:

Rules updated
Rules updated (v6)

Now we’ve allowed the OpenSSH connection, it’s safe to enable the firewall with:

ufw enable

The system warns about the possible risks of enabling ufw, but, as we’ve taken care to preserve our OpenSSH connection, we can allow the action by responding with a y as follows:

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

To double-check that our SSH connection won’t be cut when we restart the system, we can ask it to list the enabled apps with:

ufw status

The server confirms that ufw is active and shows the apps to which it allows access and from where it allows this:

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)

OpenSSH is the only app enabled at present, so we’ll need to add others as we build the LEMP stack, but we can be sure that we’ll be able to communicate with the virtual machine via SSH now the firewall is active.

Setting up SSH key authentication

DigitalOcean SSH Keys setup guide

To set up the SSH keys, I’m switching to DigitalOcean’s tutorial How to Set Up SSH Keys on Ubuntu 22.04.[3]

Before moving on to connect to the server using the non-root user account we created, this is a good point to set up SSH key access. As I noted in the previous post, you can add SSH keys when creating your Droplet allowing you to log in as root without using a password. I prefer to add the SSH keys during the setup process as it feels like a natural part of securing the server.

SSH keys are a way to log in via SSH that’s both simpler and more secure than using passwords. They are divided into pairs with public and private components. Private keys stay in a directory on computers you use to connect to the server, while you copy the public key to a similar directory on the remote machine. When you log in to the server, SSH checks that the public and private keys match and allows the connection if they do. It’s possible to set a password in addition to SSH keys if you prefer a belt-and-braces approach to server security, but if your computer is secure and only you have access to it, SSH keys can do away with needing to enter another password.

Generating a SSH key pair

Avoid overwriting existing key pairs

Skip this part of the process if, like me, you’ve generated a key pair previously that you’re using to log in to other VMs. Generating a new key pair will overwrite your existing keys, locking you out of your other setups. If this is your situation, go to Copying the public SSH key to the server below. If you haven’t generated a key pair yet, you will need to do the following.

You need to generate a key pair on your local computer, not on the server on which you’ve been working, so open a new Terminal window on MacOS or Linux or a new Command Prompt window on Windows, and enter:

ssh-keygen

The system responds with:

Generating public/private key pair.
Enter file in which to save the key (/your_home_directory/.ssh/id_rsa):

Hit return to save the key pair in the directory shown.

If you’ve generated a key pair previously, the system will warn you:

/your_home_directory/.ssh/id_rsa already exists.
Overwrite (y/n)?

This is your last chance to avoid losing your existing keys and with them access to your other servers permanently — answer n and go to Copying the public SSH key to the server. If you reply y or just haven’t generated keys before, you should be prompted to:

Enter passphrase (empty for no passphrase):

DigitalOcean’s tutorial[4] recommends setting a password here, and this is the more secure way of logging in — using both SSH keys and a passphrase associated with them.

After you’ve typed and retyped the new password, the system displays the SSH key details:

Your identification has been saved in /your_home_directory/.ssh/id_rsa.
Your public key has been saved in /your_home_directory/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Hbpy/0y+jYcvgAcmlH1vJyaX55xnLnOAzL3SUYtWlhg username@host
The key's randomart image is:
+--[ED25519 256]--+
|       o         |
|      o . .  E   |
|     .   ... .o .|
|      . oo..B.o+.|
|       oSo.B O+o.|
|        ..o +oB.o|
|      . o. .oo B |
|       o . ++o* o|
|          ..**o+ |
+----[SHA256]-----+

This completes the process of generating an SSH key pair. You’re now ready to copy the public key to the server.

Copying your public SSH key to the server

Switch to working on your local machine

If you skipped the above section on generating SSH keys, you need to copy your existing ones from your local machine and so need to do the following using a local command line. To keep the root connection with the server, open a second Terminal or Command Prompt window and do the following in it.

DigitalOcean’s tutorial[5] offers three ways of copying your public SSH key to your server — doing so automatically using ssh-copy-id, via SSH or manually. While I’m taking the ‘scenic route’ in much of this walk-through, here I’m going to go the easy way — follow DO’s guide if you’d like to copy your public SSH key to your server via SSH or manually.

Despite what DO’s tutorial says about its being included by default in most operating systems, I found I needed to install ssh-copy-id when trying to use it the first time on MacOS. You can find information on installing the utility on a Mac on the ssh.com website,[6] which also offers a guide to generating the keys. ssh-copy-id is native on Linux, but unavailable on Windows, so you’ll need to work through the section of DO’s guide on copying the keys manually if you’re working with a Microsoft operating system.

Using ssh-copy-id, it’s just a matter of using the command and specifying your username and server to which your public SSH key is to be copied. As we’re going to use the non-root username we created earlier to connect to the server, we need to copy the SSH public key to that account. Enter:

ssh-copy-id your_non-root_username@your_public_IP

You’ll be asked for the password for the non-root username we set earlier, and ssh-copy-id copies your public SSH key to the server — as DO’s guide points out, it copies the ~/.ssh/id_rsa.pub key from your local computer and adds it to the authorized_keys file in your non-root user’s home directory (/home/your_non-root_username/.ssh/authorized_keys) on the remote host.

Check that this has worked by attempting to log into your server with:

ssh your_non-root_username@your_public_IP

If you set a passphrase for your SSH private key, you’ll be prompted for this, if you didn’t set one (and all has gone well), you’ll log in immediately. (Notice that the command prompt when logged-in as a non-root user is a $ instead of a # when logged-in as root.) The next step is to disable password access so that users can only connect to your server using the relevant SSH key pair.

Disabling SSH password access

Make sure you have SSH key access to your server

Since this step will block the way in which we’ve connected to the server so far, it’s important to be sure that SSH key access is working or we’ll be unable to log in again. If you were able to log in with your non-root username after copying your public SSH key, it’s okay to go ahead with the following changes. It’s wise to open a second Terminal or Command Prompt window and log in again so that you’ll still have an open connection to reverse the process if you find that you’re unable to log in after disabling password access.

Having logged in using our newly-created non-root username, we’ll now use this in preference to the root user with which we performed the initial setup. Many of the commands we’ll be using here require root privileges, so we’ll need to enter sudo before the commands to be able to run them.

The way to disable SSH password access is by making changes to the SSH daemon‘s[7] configuration file, sshd_config, located in the server directory /etc/ssh/. To do this, we’re going to use the nano editing tool.

Using nano

I’ve often attempted to use nano in the way I would a basic desktop text editing app — particularly when it comes to copying and pasting code from and to it. nano is more rudimentary than its desktop equivalents, though, and you need to get used to its differences to WYSIWYG text editors. The utility overlays the commands you have typed previously in your server session, but this doesn’t form a separate window as it would on a desktop. If, for example, you were to try to select all the code in the nano editor and copy and paste it into another application, you’d find that you had copied the entire contents of the current SSH session — your previous commands and the server’s responses to them — as well as the relevant code. This can mean that you’ve copied a substantial amount of irrelevant text from which you need to pick the pertinent part. nano displays a series of menu options (see the screenshot below) that you access by pressing ctrl and the relevant option letter. It helps to get used to editing using nano‘s menu options rather than attempting this using the more familiar desktop manoeuvres.

To edit sshd_config in nano type:

sudo nano /etc/ssh/sshd_config

You’ll need to enter the password you set for your non-root username to run the sudo command — the system won’t ask for your password every time for a short succession of sudo commands, but it will require it again if you allow enough time to elapse between instructions.

nano displays as follows:

Editing sshd_config with nano
Editing <code class="" data-line="">sshd_config</code> with <code class="" data-line="">nano</code>

Press ctrl and W to activate nano‘s ^W Where Is menu option, type PasswordAuthentication into the search field and hit return. nano brings you to the relevant directive (setting) as follows:

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes

As the comment above the PasswordAuthentication directive says, you need to change PasswordAuthentication yes to PasswordAuthentication no. When you’ve done this, save and exit sshd_config by pressing ctrl and X, answering y to save the changes, and hitting return to save them with the same file name.

To run the SSH daemon with the amended configuration, we’ll need to restart SSH by entering:

sudo systemctl restart ssh

We’ve now disabled password SSH access, so it’s important to check that we can still log in without it. DO’s guide recommends opening up a second Terminal or Command Prompt window to check that you can still log in. In the new window, enter:

ssh your_non-root_username@your_public_IP

If the remote host reconnects after asking for your private SSH key passphrase (or not, if you didn’t set one), you’ve taken the above steps to secure the server successfully. If not, you’ll need to explore using your open connection to find where you’ve gone wrong.

We’ve now completed the initial steps, put the L into LEMP stack, and can progress to installing Nginx.

Notes and references[+]

Leave a reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.