When moving from a web hosting control panel like cPanel to a command line interface (also known as "Secure Shell" or SSH for short), it's totally understandable that you might feel a little apprehensive or intimidated. After all, you're going from a new 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 setting things like firewalls up, and taking other steps to secure and optimise your server. Where would you even begin when all you have in a cursor blinking back at you?
That's exactly how I felt when I first started making websites back in 2004. The thought of only typing commands into a text only interface scared me to death and so I persisted with cPanel for a long time.
Then I discovered EasyEngine. EasyEngine is a command line interface similar to WordOps (that I now personally use and recommend) that 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 as simple as typing:
wo site create thisismydomain.com --wp
I'll cover WordOps thoroughly in another post though. This particular 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 - 18.04.3 LTS being the most recent LTS version 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 2023.
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. On Mac you can use the built-in Terminal app to access your server via SSH, while Windows users should try Putty.
Table of Contents
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 edit (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 keep 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 check carefully 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 45.33.64.09 for example, on port 22. The IP address is an example only. In reality you'd swap out the "
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 (basically non-encrypted web pages) and port 443 for HTTPS (encrypted webpages).
apt-get update && apt-get upgrade reboot now
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. As I said in this article, root is the highest form of access and the highest administration account that you can have on your server. When you are logged in as root you can see all the files and do absolutely anything, including deleting the contents of the entire hard-drive.
And because it's likely that your web host either emailed your password to you, or you wrote the password in 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 rock.
Note that I only have a Macbook and aren't familiar with this process on Windows PC. So I will defer to this site, will has instructions for creating SSH keys for Windows.
First, on your local or home machine (your Macbook), run this command.
[/shell]ssh-keygen -b 4096[/shell]
When you are enter to choose passphrase, think of something that is going to be easy for you to recall and type (i.e. it doesn't have to be a totally secure, 30 character long mix of (un)capitalised letters, numbers and symbols).
Once that step is done, login to your server and run these commands:
cd /root ls -al
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):
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 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 gain you 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 (i.e. Mac):
scp -P 22 /Users/<your username>/.ssh/id_rsa.pub root@<your server IP>:/root/.ssh/uploaded_key.pub
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 local machine/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 local machine/Macbook 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 following two lines if they do not already exist:
PermitRootLogin without-password RSAAuthentication yes PubkeyAuthentication yes
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
... and we're done! 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 port of SSH from the default port of 22, so something else random, like 43671. This way, if a hacker is scanning your server and trying to find the SSH port to attempt to login, they won't find it if they are only trying on port 22. So 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:
Quick note on commenting: 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 means that SSH would ignore whatever was typed there and just use the default port 22. That's why we need to remove the comment (hash) when we change the port, so that the SSH program will read the line and change the port. Comments are also used by programmers to leave notes about what lines or code they are writing does.
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 login attempts that someone is able to have before their SSH connection will be closed. Do that by inserting the following (you can change the numbers if you want):
MaxAuthTries 3 MaxSessions 5
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 ports on your server as thousands of doors on your server, and each one can/might connect to different programs that are running on your server. The doors can let internet traffic both in (directed towards your server) or out (originating from your server). A firewall is a type of software (in this instance, you can also get hardware firewalls, but don't worry about them) 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:
*filter # Delete all existing rules -F INPUT -F OUTPUT -F FORWARD # 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 COMMIT
iptables-restore < /etc/iptables.firewall.rules iptables -L
iptables-save > /etc/iptables.up.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 126.96.36.199 (for example). This IP address lets people that wish to visit your website find it 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 2001:0db8:85a3:0000:0000:8a2e:0370:7334.
Anyway, 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:
sysctl -p cat /proc/sys/net/ipv6/conf/all/disable_ipv6
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 on each email and make sure that nothing looks out of place (like, for example, 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 nano /usr/share/logwatch/default.conf/logwatch.conf
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 as follows:
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 first (and 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 also. I've noticed that sometimes Logwatch email sending might fail if it is left on. You can do that as follows:
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.
service postfix restart postconf inet_protocols
By now you'll know that "root" is the highest administrative account on your server. Now 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 so that it looks like the image below. Then simply save and exit (CTRL+X) and then type "newaliases" into your shell to register the change. That's it!
And we're done! Your server is now setup securely and ready for WordOps (and WordPress) to be installed. My next guide will cover exactly that. Stay tuned!