• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Linux How to secure a Linux server

222222

Intermediate OT User
Joined
Jul 3, 2007
Messages
207
Reaction score
145
Hello!

This tutorial aims at teaching you how to secure a Linux server.
I'll be using Debian for this guide. If you're using Fedora or Arch based systems, it will be slightly different.
It's important that you take some precuations while setting up a server, whether that's for an OT server, a web server for your website or just something else.

The steps provided in this guide will in most cases be sufficient enough.
There are always more stuff you can do and it's a never-ending rabbit hole once you dive into Linux security.
But hopefully this will be sufficient for your use cases.



Step #1: Changing server SSH port
When you access your server, you will most likely do this via SSH. The default port for this is 22.
Instead, you want to change this port to something else to make it a little bit harder for people to know.
First, login to your server using SSH:
Code:
ssh root@<ip address>
Once logged in, edit your SSH configuration file by doing this:
Code:
sudo nano /etc/ssh/sshd_config
This will open up the configuration file in the text editor called Nano.
Go to the line that says "
#Port 22". Uncomment the line by removing the hashtag and then setting it to any new port number.
For this example, we will set it to "
Port 22077". Again, you can basically use any random port number if you want.
Save the file and close it, by pressing:
Ctrl+O --> Enter --> Ctrl+X

Close the connection to the server (by typing: exit) and try reconnect using SSH.
This time you will get an error and you're asked to provide a port number as well.
To connect to your server, you now have to provide the port number like this:
Code:
ssh root@<ip address> -p 22077
Verify that it works when you provide the port parameter ("-p").



Step #2: Use SSH keys with strong encryption
Instead of simply using a username and password to authenticate via SSH, it is best to use a SSH key. That means you will not only have to provide a password when connecting to your server, but also have a key file that you keep somewhere safe. Without the key, you can not enter the server. This is basically two-factor authentication for SSH and it's much more secure than a regular password.

When creating an SSH key file, you encrypt it using a cryptographic algorithm. The most commonly used is an RSA encryption, which is also the default in most cases. But there are better encryption methods out there. Instead, you want to use
ED25519 encryption for your SSH keys as they are proven to be more difficult to decrypt, but at the same time they do not cause any performance issues. If you want to read more about ED25519, you can do that here: EdDSA - Wikipedia (https://en.wikipedia.org/wiki/EdDSA#Ed25519)

To generate an SSH key for your server, open up a terminal on your computer.
I'm assuming you're using Linux on your own computer as well.
If you're using Windows, lookup how to generate SSH keys with ED25519 on Windows. It might be slightly different.
And type the following into the terminal (on your computer, not the server):
Code:
ssh-keygen -t ed25519 -a 100 -C "My OT Server"
When prompted, save the file to your desktop and name it anything you want, e.g. "otserver".
This will create a SSH key pair. You will end up with two files on your desktop.

  • otserver
  • otserver.pub
The "otserver.pub" file is your public key file. This is the one you want to keep on your server.
The other file
"otserver" (without any file extension) is your private key that is used to connect to it.
Think of the public file as the keyhole and the private file is the key that matches.
Do not share the private key with anyone, unless you want to give them access to your server.

Now you want to copy your public key
("otserver.pub") to your server. You can do this safely using the "ssh-copy-id" command.
Type the following into your terminal window (on your computer, not the server), assuming your key files are located on your desktop.
Change the "
<ip address>" to the ip address of your server. If you use a different port than 22077, change it to the port you chose in step 1.
Code:
ssh-copy-id -i ~/Desktop/otserver.pub -p 22077 root@<ip address>
The key file has now been copied ("installed") on to your server.

Now we have to edit the SSH configuration to go from "password authentication" to "SSH key authentication".
Connect to your server and edit the SSH configuration file:
Code:
sudo nano /etc/ssh/sshd_config
Change the line "
PasswordAuthentication yes" to "PasswordAuthentication no".
Uncomment the line "
#PubkeyAuthentication yes" by removing the hashtag.
Then restart the SSH service on the server:
Code:
sudo systemctl restart sshd
Exit from the server, by typing "
exit" until you're out.

To connect to your server using the SSH key file, type the following (assuming you're in the same directory as your private SSH key file "
otserver").
Code:
ssh root@<ip address> -p 22077 -i otserver
Verify that it works fine when you provide the SSH key as identification ("-i") and that it doesn't when you don't provide it.


Step #3: Create a non-root user & disable root login
When we enter the server through SSH we have so far authenticated to the "root" user account that is added to all servers by default.
But that's bad practice. We typically don't want to use "root" as the username for the SSH login, because everyone knows that username.
Instead, we will create a new user and then disable "root" from logging in to the server.
This means anyone who wants to access your server needs to know the new username.

So first, we will create a new user on the server. So make sure you are connected to it via SSH and then type the following command:
Change "<username>" to whatever you want. Pick something really random.
Code:
useradd -m -s /bin/bash <username> && passwd <username>
This will add a new user and then let you choose a password for it. Use a very strong and unique password that you don't use anywhere else.

My recommendations:
For the username, I use the old Tibia "suggested name" generation, which is basically this: "Consonant + Vowel + Consonant" a few times repeatedly. You remember the old characters names in Tibia? They were quite unique, but also easy to remember. If you want to know how to generate a such name, here's the JavaScript code for it. Simply copy-paste this into the "console" of your browser and you will get randomly generated names:

Code:
function randomName() {
    let name = "";

    // Letters
    let vowels = ["a", "e", "i", "o", "u"];
    let consonants = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z"];

    // Name and length
    let length = Math.floor(Math.random() * (10 - 5)) + 5;

    // Generate a new name
    for (let i = 0; i < length; i++) {
        if (i % 2 === 0) name += consonants[Math.floor(Math.random() * consonants.length)];
        else name += vowels[Math.floor(Math.random() * vowels.length)];
    }

    return name;
}

And run it in your browser like so:
Code:
console.log(randomName());

So for example, it generated the name "
wineredo", this will be my new username for the server.
For the password, I'm using
KeePass XC to both store and generate strong passwords.
I highly recommend you get a password manager like KeePass XC.
Create a strong and unique password.

So when you have created your new user for the server, make sure it was created successfully.
Check that it appears here:
Code:
cat /etc/passwd
To make the new user able to run sudo (admin commands), check what the name of the admin group is - and then add the user to that group.
In most cases, the group will simply be called "sudo". But double check it by running:
Code:
visudo
Find the name of the admin group ("%"). Again, usually it is just "sudo".
Once you know the name of the group, e.g. "sudo", then add the user to that user group like this:
Code:
usermod -aG sudo wineredo
In my case, I add it for user "
wineredo". Change it to your username.
Also verify that the user was successfully added to the "sudo" group by typing:
groups <username>
Now try to enter elevated privileges with the new user and run an "apt update" as a test:
Code:
su - <username>
sudo apt update

Now that the new user is created and can access admin rights, we will restrict the SSH access to the server.
We will remove the user "root" from being able to connect, and only make it possible for this new user.
Edit the SSH configuration file by opening it using the text editor Nano:
Code:
sudo nano /etc/ssh/sshd_config
Change "
PermitRootLogin" to "no".
Add a new line anywhere in this file called "
AllowUsers" followed by the usernames that you want to give SSH access to.
In my case, I will only add it to my new user called "
wineredo". I will type the following line into the file:
Code:
AllowUsers wineredo
If you want to add multiple users, separate them by spaces on the same line.

Now attempt to login using the "root" account to your server. It will result in an error.
Instead, try to login using your new user account. That will work, as long as you also provide the port number and the SSH key file.
Code:
ssh <username>@<ip address> -p 22077 -i otserver


Step #4: Setup and enable firewall protection
It is crucial that you install and configure a firewall on your server. Without it, you will be much more vulnerable.
We will install and then set it up, and only allow certain port numbers to function on your server.
Why enable all ports? Instead, we only allow the ones that are in use.
And by default, we block all incoming connections - and allow all outgoing communication.
Such as these ports:

  • 80 (HTTP) for the website, if you have one
  • 443 (HTTPS) for the website, if you have one
  • 3306 (MySQL) for the database, if you have one
  • 22077 (SSH) or whatever port number you chose, this is important! Otherwise you can't access via SSH!
  • 7171 & 7172 (Tibia) so that players can access your OT server.
We do this by installing "ufw" (firewall software) and then configuring it.
Connect to your server and run the following with admin privileges:
Code:
su - <username>
sudo apt update
sudo apt install ufw
sudo systemctl enable ufw
sudo systemctl start ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 3306
sudo ufw allow 22077
sudo ufw allow 7171
sudo ufw allow 7172
sudo systemctl restart ufw


Step #5: Prevent bruteforce attacks
Your server will most likely end up getting a lot of bruteforce attacks where bots will try to login to it via SSH and steal/corrupt your files. This happens to millions of servers in the world every year. We can make it very difficult for someone to attempt that by limiting the amount of requests they can make to the server in a given time period. For example, if they enter the wrong SSH password 3 or 5 times we can set to block them for 1 hour. If they repeat it, it will be a 24 hour ban, and so on. This will make it more difficult for them, since they need to keep changing IP addresses over and over.

To do this, we can use a program called "
fail2ban" which is one of the most popular ones for mitigating bruteforce attacks.
First, we will install it and then configure it (maximum login tries, bantime, etc.).
Then we need to specify where we want to apply it. This is what most people forget about.
They set it up, but don't enable it, which means it has no use.
In our case, we want to set it for the SSH access and nothing else.
We do not want to enable it on everything, for example the OT server. Imagine a player enter incorrect password and gets banned 1 year for it. That would be bad for the server.

Login to the server using admin privileges and run the following:
Code:
sudo apt install fail2ban
cd /etc/fail2ban
cp jail.conf jail.local
sudo nano jail.local
So with the above commands, we installed it, went to its install directory, copied the default setting file and opened it up.
Now we will edit the file.

Set the
bantime to 60 minutes.
Set the
maxentry to 5 times.
This means if someone will enter the wrong SSH credentials 5 times in a row, they will get a 60 minute ban.

Now we need to enable the different "jails" that we want to apply fail2ban for.
Each "thing" that we want to enable this for, is called a "jail".
Like I mentioned above, we want to enable this for SSH.
Scroll down and you will see a section for the SSH jail ("
sshd").
Add the line "
enabled = true" to enable this for SSH access.

You can also set to whitelist some IPs, for example your home computer, for unlimited login attempts to SSH.
Simply uncomment the "
#ignoreip" line and then add IP addresses after it, separated by spaces.
For example, if my home IP is 123.123.123.123 I will whitelist it using this line in the "sshd" jail:

ignoreip 123.123.123.123

You can then also set a logpath where you will see all the connection attempts that you're getting.
For example, my "
sshd" jail looks like this:
Code:
[sshd]
enabled = true
port = 22077
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 60
ignoreip = 123.123.123.123

I set it to be enabled for my specific port (22077), each log entry will be identified as "sshd", I gave it a log path, max entries, bantime and I whitelisted my home IP address to give unlimited login attempts.

Save the file, using
Ctrl+O --> Enter --> Ctrl+X

After you have set up the jail for the SSH access, simply restart fail2ban and double check to make sure it is started:
Code:
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban
sudo systemctl start fail2ban


Step #6: Frequently check your server and log files
That was it. You have now secured your Linux server, at least enough for most type of attacks.
We have set a custom SSH port, created a new user account, disabled root login, enabled SSH key login, configured a firewall and prevent bruteforce attacks on the SSH service.

There is much more that you can do if you put time and effort into learning about it. But this should be sufficient for most use cases.
Now all that's left is that you frequently login and make sure everything is working as intended.
Keep an eye on the SSH logs in
/var/log/auth.log

Store your passwords in a password manager like KeePass XC, and keep your SSH key files safe and secure. Do not share them with anyone.
I recommend not storing them in any cloud service, instead keep them on a USB or external drive.
You do not need to update your server and services. This is not like Windows.
Unless there is some known vulnerability out there, you have no reason to update stuff all the time.
When updating, sometimes some things can break. Or sometimes services stop auto-restarting.

To check if for example your firewall is running, or if fail2ban is running, use the "systemctl status" command.
As an admin user, run the following to check statuses for firewall and fail2ban:
Code:
sudo systemctl status ufw
sudo systemctl status fail2ban
If they are not "active (running)", then enable them (enable means autostart) and then start them:
Code:
sudo systemctl enable ufw
sudo systemctl enable fail2ban

sudo systemctl start ufw
sudo systemctl start ufw

And remember, security is a journey - not a destination. There's always things that can be improved.
By doing something is however much better than doing nothing.
Also, pick a trusted hosting provider. I can highly recommend DigitalOcean's services. They have fantastic support, good uptime and affordable prices.

Good luck and I hope this helps someone out there.
Also remember to make backups of your database from time to time, in case anything happens to your server.
 
Last edited:
Awesome tutorial, thanks for sharing it with the community!

You're welcome! I hope this tutorial will be useful for someone out there who's just getting started with Linux servers.
An important thing to also remember is if you add any kind of new port to the server, it needs to be added to the firewall as well.
And remove unused ports from the firewall if you ever change them in the future.
Only allow what's being used on the server and nothing else :)
 
Thanks for putting the time into making this. I'm sure it will be helpful :)

A bit more advanced, but CrowdSec (Open Source Crowd-Sourced Security Engine, Community IP Blacklist) may be worth a look:



"CrowdSec is a free, modern & collaborative behavior detection engine, coupled with a global IP reputation network. It stacks on fail2ban's philosophy but is IPV6 compatible and 60x faster (Go vs Python), it uses Grok patterns to parse logs and YAML scenarios to identify behaviors. CrowdSec is engineered for modern Cloud / Containers / VM-based infrastructures (by decoupling detection and remediation). Once detected you can remedy threats with various bouncers (firewall block, nginx http 403, Captchas, etc.) while the aggressive IP can be sent to CrowdSec for curation before being shared among all users to further improve everyone's security." (Taken from GitHub description)
 
Last edited:
Thanks for putting the time into making this. I'm sure it will be helpful :)

A bit more advanced, but CrowdSec (Open Source Crowd-Sourced Security Engine, Community IP Blacklist) may be worth a look:



"CrowdSec is a free, modern & collaborative behavior detection engine, coupled with a global IP reputation network. It stacks on fail2ban's philosophy but is IPV6 compatible and 60x faster (Go vs Python), it uses Grok patterns to parse logs and YAML scenarios to identify behaviors. CrowdSec is engineered for modern Cloud / Containers / VM-based infrastructures (by decoupling detection and remediation). Once detected you can remedy threats with various bouncers (firewall block, nginx http 403, Captchas, etc.) while the aggressive IP can be sent to CrowdSec for curation before being shared among all users to further improve everyone's security." (Taken from GitHub description)

Never heard of CrowdSec before. I'll definitely be checking it out and see if it works good on my e-commerce sites. Thank you for sharing that!
 
[...]
Code:
su - <username>
sudo apt update
sudo apt install ufw
sudo systemctl enable ufw
sudo systemctl start ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 3306
sudo ufw allow 22077
sudo ufw allow 7171
sudo ufw allow 7172
sudo systemctl restart ufw

[...]

Hello.
I think a litle bit more restricted ufw rules should be better.
Code:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 22077/tcp
sudo ufw allow 7171/tcp
sudo ufw allow 7172/tcp

sudo ufw limit 2077/tcp comment 'SSH port rate limit'

And I don't think that it's a good idea to allow to connect to mysql port from outside with no strict list of IP addresses.
 
Hello.
I think a litle bit more restricted ufw rules should be better.
Code:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 22077/tcp
sudo ufw allow 7171/tcp
sudo ufw allow 7172/tcp

sudo ufw limit 2077/tcp comment 'SSH port rate limit'

And I don't think that it's a good idea to allow to connect to mysql port from outside with no strict list of IP addresses.

Fantastic stuff! Didn't know you could limit it there as well. Great addition!

Keep the thread going. If anyone knows more "good-to-know" things, feel free to share. The more, the better. We can all learn from each other.
 
Anyway fail2ban will not block custom ssh port on firewall if You don't modify /etc/fail2ban/jail.d/ssh-full.conf

It should work fine:
Code:
[ssh]
enabled  = true
port     = 22,22077
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 2
# 30 days
bantime = 2592000
 
This is awesome,
a personal edit I like to use is stated above. Allow TCP and leave out any extra exploits of UDP entries since it's not needed anyways.
Plus:

1. Keep security updates automatic, this will ensure that your system is up-2-date with all stable security updates that's coming in the future, meaning you'll not need to manually update them or simply forget to do them.

Lua:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

2. Setting up cloudflare Anti-bot or re-captcha services upon bot-exploitable vulnerabilities, such as register and mail/ticket sending.
Using Cloudflare anti-bot, removes the need of manually solving or clicking a captcha box which makes everything work in the background invisible for the eye of your player base or any browsing user.

3. Hiding /phpmyadmin into a different location, making it harder for bots to attack your database by bruteforce since phpmyadmin is the first place they'll scan for.
Nginx example:

Lua:
sudo ln -s /usr/share/phpmyadmin /var/www/html/php_hidden

Apache2
Lua:
sudo nano /etc/apache2/conf-available/phpmyadmin.conf

Change to this:
# phpMyAdmin default Apache configuration

Alias /php_hidden /usr/share/phpmyadmin

4. Making sure of HTTPS connection, or re-direct to your domain name by disabling default server block + Make sure to setup a custom server block with Let's encrypt.

Unlink default server block:
Nginx:
Lua:
// Entering sites-available directory
cd /etc/nginx/sites-available

// Showcasing existing files inside sites-available
ls

// Unlinking default server block
sudo unlink default

// Make sure the changes are valid
sudo nginx -t

// Restarting nginx
sudo systemctl reload nginx

Setting up let's encrypt with Nginx:

5. Use strong and random passwords you can't memorize.
For example, spam your keyboard.

kasjfklasfjlasjflkasjflkjlkjalkfj23123123aksfalskfjkajwr


Now add some cap marks into it.
KasjFklasfjlASjflkasjflkjlkjAlkfJ23123123aksfalskfJkajwr

Now add some special marks into it
KasjFkl@!asfjlASjfl#kasjflkjlkjAlkfJ231231#!23aksf!!al!skfJkajwr

This will ensure that a bruteforce attack isn't easy, no matter the power used. Use this for any matter, MYSQL, PHPMyAdmin, Super User etc.

6. Using Nginx instead of Apache2, faster and more secure. Sure, we don't need that extra speed for an OTServer. But it's a good thing to move over to it due to security risks.
Sure, it's not easy. However, in the future. You'll thank yourself for moving over to it since more and more market shares has moved away from Apache2 over the years due to many reasons.
You can google this and do some research, plus. I just love Nginx and it's server block. It's powerful and simple.
 
Last edited:
This is awesome,
a personal edit I like to use is stated above. Allow TCP and leave out any extra exploits of UDP entries since it's not needed anyways.
Plus:

1. Keep security updates automatic, this will ensure that your system is up-2-date with all stable security updates that's coming in the future, meaning you'll not need to manually update them or simply forget to do them.

Lua:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

2. Setting up cloudflare Anti-bot or re-captcha services upon bot-exploitable vulnerabilities, such as register and mail/ticket sending.
Using Cloudflare anti-bot, removes the need of manually solving or clicking a captcha box which makes everything work in the background invisible for the eye of your player base or any browsing user.

3. Hiding /phpmyadmin into a different location, making it harder for bots to attack your database by bruteforce since phpmyadmin is the first place they'll scan for.
Nginx example:

Lua:
sudo ln -s /usr/share/phpmyadmin /var/www/html/php_hidden

Apache2
Lua:
sudo nano /etc/apache2/conf-available/phpmyadmin.conf

Change to this:
# phpMyAdmin default Apache configuration

Alias /php_hidden /usr/share/phpmyadmin

4. Making sure of HTTPS connection, or re-direct to your domain name by disabling default server block + Make sure to setup a custom server block with Let's encrypt.

Unlink default server block:
Nginx:
Lua:
// Entering sites-available directory
cd /etc/nginx/sites-available

// Showcasing existing files inside sites-available
ls

// Unlinking default server block
sudo unlink default

// Make sure the changes are valid
sudo nginx -t

// Restarting nginx
sudo systemctl reload nginx

Setting up let's encrypt with Nginx:

5. Use strong and random passwords you can't memories.
For example, spam your keyboard.

kasjfklasfjlasjflkasjflkjlkjalkfj23123123aksfalskfjkajwr


Now add some cap marks into it.
KasjFklasfjlASjflkasjflkjlkjAlkfJ23123123aksfalskfJkajwr

Now add some special marks into it
KasjFkl@!asfjlASjfl#kasjflkjlkjAlkfJ231231#!23aksf!!al!skfJkajwr

This will ensure that a bruteforce attack isn't easy, no matter the power used. Use this for any matter, MYSQL, PHPMyAdmin, Super User etc.

6. Using Nginx instead of Apache2, faster and more secure. Sure, we don't need that extra speed for an OTServer. But it's a good thing to move over to it due to security risks.
Sure, it's not easy. However, in the future. You'll thank yourself for moving over to it since more and more market shares has moved away from Apache2 over the years due to many reasons.
You can google this and do some research, plus. I just love Nginx and it's server block. It's powerful and simple.
It's very nice that you wrote down some more valuable advice, we would like to say hello
 
Amazing tutorial and replies! I am getting a Hetzner VPS soon and this will be really useful
 
Back
Top