Running your own server can be time consuming and difficult. If you are just starting your blogging journey then I highly recommend that you begin with BlueHost. It took me several years before I was comfortable enough to move some of my sites off onto their own servers, and it is by no means required for most websites or blogs anyway. If you aren’t sure whether you need either BlueHost hosting or your own server, you probably just need BlueHost. As always, if you have any questions, then please email me.
When moving from a web hosting control panel like cPanel, or BlueHost’s custom solution, to a command line interface (also known as “secure shell” or SSH for short), it’s understandable that you might feel a little apprehensive or intimidated. After all, you’re going from a graphical interface like that below, with lots of options and explanations, to a basic command like that seems to offer no help at all.
Not to mention that you need to take personal responsibility for your site’s security now, and that of the server that it is hosted on. This means setting up a firewall and taking other steps to secure and optimise your server. Where would you even begin when all you have is a cursor blinking back at you?
That’s exactly how I felt when I first started making websites back in 2004. The thought of typing commands into a text only interface scared me to death and so I used BlueHost with cPanel for a long time.
Then I came across EasyEngine. EasyEngine is a command line interface that was the precursor to WordOps, which is what I use now. WordOps installs and sets up all the tricky stuff for you, and then offers simple commands to create new websites, edit and remove them, etc. It basically makes setting up a new WordPress site as simple as typing:
wo site create thisismydomain.com --wp
I’ll cover WordOps thoroughly in another post though. This particular article is a guide on the exact SSH commands that you need to enter once your VPS, cloud server or dedicated server has been created. By the way I personally use Ubuntu, version 20.04 being the most recent LTS release at this moment. LTS stands for Long Term Support and means that security and maintenance upgrades will be offered for five years from the time of its release, until April 2025.
I documented this process after much trial and error and now use it to initially setup and secure all my servers. I have never had a server or website hacked or compromised (fingers crossed). On Mac you can use the built-in Terminal app to access your server via SSH, while Windows users should try Putty.
Connect To Your Server
Run Updates and Reboot
Change Root Password
Create SSH Keys
Setup Iptables (Firewall)
- Check your existing firewall rules (if any).
- Edit your rules with our settings.
- Paste in the following and then save and exit (CTRL+X). You’ll see that I made the two SSH rules the same port as we changed SSH to run on in the step above, 43671. It’s critical that these numbers match otherwise you might be locked out of your server. You can also change the port for the 4 lines that relate to “WordOps Tools” to something else random in the 3XXXX or 4XXXX range. We will use this setting later when we install WordOps.
- Activate and check the rules. You should see the rules you pasted in reflected on the screen.
- Save the rules.
- Set your Iptables rules to be applied at every boot (start up) of your server. Paste in this text “/sbin/iptables-restore < /etc/iptables.firewall.rules" so that it looks like the image below. Save and exit (CTRL+X)
- Now create a new SSH session by opening another copy of your Terminal program (or other SSH client) but keeping your current SSH window open and logged in. You should be able to login via SSH to your server just like before, with the firewall letting you through. If not, then something is wrong and you should carefully check the SSH lines in your firewall rules using the command below.
- Find the line that begins with “Output” and make it as follows “Output = mail”
- Next find the MailTo line and change that to include your email address, eg “MailTo = firstname.lastname@example.org”
- You can change the MailFrom line to reflect your server, eg “MailFrom = MyWebsiteName-Logwatch”
- Change the Range as follows, “Range = between -7 days and -1 days”
- Save and exit (CTRL+X)
Turn Off IPv6 Emails
Add Root Default Email
Open your SSH client (Terminal on Mac, Putty on Windows) and type in the following command:
ssh -p 22 root@<server IP address>
This tells your computer to connect to your server at IP address 126.96.36.199 for example, on port 22. The IP address is an example only. In reality you’d swap out the “server IP address” and put the IP number of your actual server.
To understand what a port is, imagine your server having thousands of potential doors, each numbered 1 to approximately 65,000. Only a handful of the doors actually exist though, and each door is connected to a specific program running on your server. You can also change the port numbers of programs and deny access to other ports via firewalls (which we’ll talk about later).
Some default port numbers are port 22 for SSH (as above), port 80 for HTTP (non-encrypted web pages) and port 443 for HTTPS (encrypted webpages).
apt-get update && apt-get upgrade
The first “update” command tells your server to update it’s internal list of file versions and possible updates. The second “upgrade” command tells your server to actually execute the upgrade. You’ll see a bunch of text across your screen. Just hit YES to upgrade at the end of it.
We can safely do this now because your server is brand new and its quite likely that your web host company used an old server image to create it. Kind of like when you first install Windows on your home desktop and then there is a lot of updates to download from Microsoft to make it safe and secure.
The reboot command does as you’d expect and reboots your server, ensuring the updates are correctly applied and live.
Next you’ll want to change your root password. Root is the name of the highest level administration account on a server. Logging in as root means that you can do literally anything on the server, and are able to execute any command whatsoever, even ones that would wipe the entire harddrive. When you are logged in as root you can see all the files and do absolutely anything.
Because it’s likely that your hosting company either emailed your password to you, or you wrote the password on a form on their website, you should now change it to something more secure and that they wouldn’t have had access to. To do this just type:
Enter your new password twice to confirm and you’re done with this step.
Right now, each time you login to your server, you’d need to type in the password, which should be a long and complex. However, it’s possible to create something called SSH keys which will enable you to login automatically – all you need to do is type in the command into your SSH client (or have that command saved and execute it) and you’d be logged in to your server and ready to go.
Note that I only have a Macbook and am not familiar with this process on Windows PC. So I will defer to this site which has instructions for creating SSH keys for Windows. However, to create SSH keys on Mac, follow these instructions:
On your local or home machine (your Macbook), run this command.
ssh-keygen -b 4096
When you are asked to choose a passphrase, think of something that is going to be easy for you to recall and type (ie it doesn’t have to be a secure, 30 character mix of capitalised letters, numbers and symbols).
Once that step is done, login to your server and run these commands:
Check if you can see a directory called “.ssh”. If you can, great. If you don’t, run this command and don’t enter a password when prompted, just press enter:
Now you need to lock down that .ssh folder by changing what’s called the permissions. This basically ensure that only you (with the root account) can access the SSH keys you’re about to create.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/*
Next, you want to copy your local public key (that you created on your Mac with the “ssh-keygen” command above) to your server. This key file is safe to copy and send as it only allows you to access servers where it is authorised (so if someone stole it and placed it on their server, it would grant you access to their server and they gain nothing!). To operate it also needs your private key, which is something that you don’t copy and send around, so only you will have that (and not any attackers, so they can’t access your server if they only have your public key).
Execute this command on your local machine (your Mac):
scp -P 22 /Users/<your username>/.ssh/id_rsa.pub root@<your server IP>:/root/.ssh/uploaded_key.pub
Swap out “your username” with your username on your Mac of course, and well as “your server IP” for the actual IP of your server. You will also be asked for the password to login as root on your server, so paste that in.
Finally, now that your public key is on your server, you need to copy the contents of it to the authorised keys list. You can do this either on your server, or on your Mac. I’ll provide the commands for both.
On your server itself just type in:
cat ~/.ssh/uploaded_key.pub >> ~/.ssh/authorized_keys
On your /Mac type:
ssh root@<server IP> "echo `cat ~/.ssh/uploaded_key.pub` >> ~/.ssh/authorized_keys"
Remember to swap out
Finally, you should edit the configuration file of the SSH program on your server by typing the following:
Find the line that says “PermitRootLogin” and alter it as follows. Also, add the line that follows if it does not already exist:
Save the file and exit the editor by pressing CTRL+X and choosing yes to the prompt. Then you should restart the SSH program (it’s actually called a “service” in Linux speak) using the following command:
service ssh restart
We’re done with this step! Now, to test all this out, keep your existing Terminal or Putty windows open, and create a new window. In it, paste in the connection command from step 1 above:
ssh -p 22 root@<server IP address>
All going to plan, you should be logged in to your server without being asked for a password.
Security is a large part of operating your own server successfully, but luckily the steps in order to secure your server are pretty straight forward.
In this step, we are going to change the SSH port from the default port of 22 to something else random, like 43671 for example. This way, if a hacker is scanning your server and trying to find the SSH port to connect to, they won’t find it from a quick attempt.
Type in the command to edit the SSH config file:
Find the port line, it should be near the top of the file, if it is commented out like this: “# port 22” then uncomment it by removing the “# ” part and then change the port number to something random and above 30000, like 43671. Do not use commas in the number. So you should end up with a line simply like this:
Before we continue, here’s a quick explainer on commenting in files: On Linux systems like your server, when you add comments in a file by inserting “#” at the start of a line, it means that that line won’t be processed by whatever program uses the file, it will just ignore it instead. So when the port line was commented out, it meant that SSH would ignore whatever was typed there and just use the default port 22. That’s why we need to remove the comment (the hash symbol – #) when we change the port, so that the SSH program will read the line and actually change the port. Comments are also used by programmers to leave notes about the code they are writing.
In addition to changing the port you should also limit the maximum number of concurrent SSH sessions that can be open at any one time and also the maximum number of failed logins that someone is able to attempt before their SSH connection will be closed. Do that by inserting the following (you can change the numbers if you want):
Save the file and exit the editor (CTRL+X). Then, as above, you should restart SSH for these new settings to take effect. Paste in the following:
service ssh restart
As I wrote above, you can imagine the ports on your server as thousands of doors, and each one might connect to different programs that are running on your server. The doors can let internet traffic in (directed towards your server) or out (originating from your server).
A firewall is a type of software that only opens the specific ports that we want open and closes everything else off.
If you imagine your server was your home, then closing all the doors off would make it more secure right? The same can be said for your server and blocking off as many ports as we can, to keep out intruders/hackers.
Iptables is the name of the firewall that I use and you can set it up as follows:
# Delete all existing rules
# Set default chain policies
-P INPUT DROP
-P FORWARD DROP
# Accepts all established inbound TCP connections
-A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow incoming SSH
-A INPUT -p tcp --dport 43671 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp --sport 43671 -m state --state ESTABLISHED -j ACCEPT
# Allow incoming HTTP
-A INPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
# Allow NTP system time
-A INPUT -p udp --dport 123 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p udp --sport 123 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Allow outgoing HTTP
-A OUTPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
# Allow incoming HTTPS
-A INPUT -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
# Allow outgoing HTTPS
-A OUTPUT -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
# Allow incoming WordOps Tools
-A INPUT -p tcp --dport 31837 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp --sport 31837 -m state --state ESTABLISHED -j ACCEPT
# Allow outgoing WordOps Tools
-A OUTPUT -p tcp --dport 31837 -m state --state NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp --sport 31837 -m state --state ESTABLISHED -j ACCEPT
# Allow Sendmail or Postfix
-A INPUT -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp --sport 25 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Ping from inside to outside
-A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
# Ping from outside to inside
-A INPUT -p icmp --icmp-type echo-request -j ACCEPT
-A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
# Allow loopback access
-A INPUT -i lo -s 127.0.0.1 -j ACCEPT
-A OUTPUT -o lo -s 127.0.0.1 -j ACCEPT
# Allow outbound DNS
-A OUTPUT -p udp --dport 53 -j ACCEPT
-A INPUT -p udp --sport 53 -j ACCEPT
# Allow inbound DNS
-A INPUT -p udp --dport 53 -j ACCEPT
-A OUTPUT -p udp --sport 53 -j ACCEPT
# Enable all outbound TCP
-A OUTPUT -p tcp -j ACCEPT
# Drop all UDP traffic
-A INPUT -p udp -j DROP
-A OUTPUT -p udp -j DROP
# Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
iptables-restore < /etc/iptables.firewall.rules
iptables-save > /etc/iptables.up.rules
At this stage, if there is a problem, it is very important that you keep all SSH windows open, because you will need to fix up the port error. The port number that you changed your SSH service to run on must be the same number that you inserted into your Iptables rules.
IPv6 is the “next” version of the Internet Protocol. In a nutshell, when it is deployed, your server will be given an IP address like 188.8.131.52 (for example). This IP address lets people find your website and it is linked to your domain name.
A number in the aforementioned format is IPv4. An IPv6 address on the other hand looks like 0:0:0:0:0:FFFF:982C:2D10.
IPv4 is all we need to worry about for now (it still works excellently for our purposes) and I have noticed that sometimes leaving IPv6 on can interfere with various programs and other things on the server. So we will disable it with the following commands.
Insert the following at the very end of the file (handy hit: press CTRL+V to jump down a page):
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
Then run these two commands:
If the final command reports back a “1” then you have been successful in disabling IPv6.
LogWatch is a handy program that we’ll install to keep an eye on our server. It will automatically send us a weekly email with some high level statistics about, for example, what new software was installed, deleted or upgraded on the server, who logged in via SSH and their IP addresses, disk space usage statistics and more.
It’s good to run through each email and make sure that nothing looks out of place (like, for example, if there is one or more SSH logins from IP addresses you aren’t familiar with, or if your free disk space is getting dangerously low). We can install and setup LogWatch as follows:
apt-get install logwatch
Next you want to move the cronjob for LogWatch to the weekly folder. A “cron” is a job or task that your server will run automatically at an interval that you set. Currently, the LogWatch task is in the daily folder and so you will get a LogWatch email each day. We only want one each week, so we’ll move it with this command:
mv /etc/cron.daily/00logwatch /etc/cron.weekly/
Finally, you can test if LogWatch is installed and working correctly by simply typing “logwatch” in your shell. You should shortly receive an email with some info on your server. If you don’t, check your spam folder. You might need to set up some filtering rules to ensure that future Logwatch emails don’t go to your spam folder – particularly if you use Gmail.
We turned off IPv6 before, but now we’re going to turn it off specifically for emails too. I’ve noticed that sometimes Logwatch email sending might fail if it is left on. You can turn off IPv6 for email by editing the following file:
Change the line “inet_protocols = all” to “inet_protocols = ipv4”. Then just run the following commands. The last command is a check to see if it worked, and should return only IPv4 if you’ve done this step correctly.
service postfix restart
By now you’ll know that “root” is the highest administrative account on your server. In this final step, we are going to set a default root email address that any important system messages will be sent to. Do this with the following:
Add “root: email@example.com” to the last line, then simply save and exit (CTRL+X) and then type “newaliases” into your shell to register the change.
We’re done! Your server is now setup securely and ready for WordOps (and WordPress) to be installed.