Objective: SSH Hardening and Server Security
The video focuses on securing a newly provisioned server before production use. The goal is to enforce strict SSH access controls and apply essential security configurations through a reusable bash script.
Core Security Principles
Root login must be disabled, and password-based SSH authentication must be turned off. Access should only be allowed via SSH keys to ensure that only authorized users with the correct private key can connect.
Admin User Setup
A dedicated admin user is created with a home directory and added to the sudo group. This user must authenticate with an SSH key to log in and provide a password for privileged (sudo) operations.
SSH Configuration Hardening
The script modifies SSH settings to disable root login, disable password authentication, enforce key-based access, limit login attempts, restrict sessions, and allow only specified users. The default SSH port is changed, and only essential ports are left open.
Fail2Ban Integration
Fail2Ban is installed and configured to monitor failed login attempts and automatically ban IP addresses after repeated failures. This reduces brute-force risks and lowers unnecessary server load.
Firewall Configuration
A firewall is configured to allow only HTTP (80), HTTPS (443), and the custom SSH port. All other ports are closed unless explicitly required, such as for a public database.
Script Execution and Validation
The hardening script is uploaded, executed, and the server is rebooted. Verification confirms that root login is blocked, SSH access requires the custom port and key authentication, and administrative actions require a password.
Next Steps
With SSH security in place, the next step is to configure a reverse proxy (Caddy) and associate a domain to enable HTTPS for securely running the application.
Okay, we have our server, we can SSH into it, but there's still a bunch of security measures we should take before we start to run or use this server for production usage. This is basically SSH hardening and server security. So what we're gonna do in this episode is I'm gonna walk through or explain what we're gonna do. Then we're gonna copy paste a big script that we're gonna create as a batch script and have that run on the server.
that will apply all the things we'll touch upon in just a second. And then our server is pretty much ready to use. We still need to install a reverse proxy. We still need to get our binary onto the server, but our server from our security standpoint after this episode will be ready to use. So the two golden rules, the two minimum things we need to have in place for this to be secure is we have to have no root login.
because the root user that we are logged in as now has no restriction as to what they can do and perform on the server. And we need to require that all access happen through SSH keys. So out of the box, SSH is functional, but root login is allowed, password authentication is allowed, there's no rate limiting on failed access attempts. So one of the goals is that only
authorized users with the proper SSH key can access the server. And even if our attacker or hacker were to know our username, they will not be able to get in unless they somehow got a hold of our private key. So the first thing we're going to do is we're going to disable the root login. We will disable password authentication, and then we will create a
a separate user that's going to be our admin user that we will then log in with. And that user will be required to use a password when that user is on the server. So we can still switch to the root user if we want to. But you will need the private key to access the server first. And then you need to change to the root user from our new admin user and provide the password that we are going to be creating for that user.
Let's walk through this SSH hardening bash script that we're gonna run on the server in just a second. Out of the box, SSH is functional, but it's not secure enough. We still can log in with root, as we just saw, which means that we can perform actions without any restrictions. We can log in with password. There's no rate limiting on failed login attempts.
So the goal here is to create a specific user that we will use to interact with our server. We will also make sure that you can only get into the server with a key that we know about. And we'll also make sure that the user we create has to provide a password on the server to be able to perform admin actions. So one of the main goal here is simply that we know who
and who can access the server and who can do what on the server. And in this case, it's only going to be us. But you could technically repeat this process for other users if you want to give them access to the server. You'll simply create another user and add another public key, and then they can access the server from their own computer. Right, so we have some ENV variables here that you can overwrite before running the script.
Here, we default to admin. If a username is not provided, we can specify a password as our ANV variable, or we can use this OpenSL command. We can also provide the SSH key and the SSH port and the time zone, which is I'm going to be setting to Europe slash Copenhagen. Right. We do a little bit of validation here. That's not the most
important part and we do some system update that we already run this is just for good measure and then we get to creating the user and here we simply check if the user name is set and if it is then we're going to add the user and we are specifying the dash M so we also get a home directory for the new user we then add this user to the sudo group but we also specify that they will require a password to do in a sudo
actions. Then we add this SSH key, the public key, to this user's home directory again in slash dot slash home slash username slash dot SSH. Just assist on your own computer. We add the key to offer as keys. We set some permissions so that we can use the key. And then this new user can log into the server.
with the private key that we have on our computer. We will then install some packages. We are going to be using Curl to get some tools onto the server. We're going to be using failed2ban, which is a package that will make it so that you can just try a lot of things over and over and over again. It will literally ban the IP address that's tried to
to access a server many times and failing to do so many times. So this is just an extra security measure that makes it so that we guarantee that we can just keep trying and trying and trying without any consequences. And now we get to the more SSH hardening part of this setup. I typically change the port. What you want to do on the server is you want to allow
a port alien for HTTP access and port what is it 443 for HTTPS. And then I also changed the SSH port to something other than port 22 because other hackers will know that this is a default port. And then we close all other ports. So that's the only three ports you can access our server through. Then we simply go through a bunch of security changes.
We go in and say that you cannot log in as root. We have password authentication set to no. We enable the key-based authentication. We don't permit empty passwords, so users cannot use an empty password. We also disable keyboard interactive off with the challenge response authentication.
We also said we have some max of tries here. You can only try three times before you get automatically disconnected from the server. So again, it's a little bit of a measure to slow down brute force attacks. We limit the number of sessions that can be per connection. We also have our little client. Client, there we go.
a live interval check so that we check every five minutes if the client is still alive. We disconnect after two failed checks. This also is a measure to help prevent dead connection from hanging around. We go in and say, allow users to our username. So if you add other users to your server, you would need to go in and change
this file right here, the SSHD underscore config, and provide more user names after this. Great. So this is the basic SSH hardening we are going to be doing. And I think changing the SSS port is important. We have more the permit root login to know, and then also making sure that password authentication is set to know. That's the main things that you kind of have to do.
Next we configure fail to ban and it's basically a monitor that locks for fail login attempts and automatically block IPs that fails too many times. So we set the ban time, we set the retry, we specify how many attempts they can have and also we ban them for like an hour, yeah, for an hour. We specify the port
So that even if you're trying to authenticate also have with our SSH key, that will also put you in jail if you continue to fail. And it helps reduces the server load because they can just keep pinging the server, so it will just immediately block them. Right. Next, we do some hard, so some firewall configuration.
What I mentioned earlier, we only want HTTP and HTTPS as well as the SSH port that we set. So this is just a really good security measure to make sure that we only allow three ports here. If you were to install Postgres and you want to access Postgres from outside of the server, you would also need to open the port that Postgres is listening on with as per default is 5,4,3,2.
which we also have to set up, so we have a database, but that's for a different episode. Anyways, when we get to that, we need to change these settings. If we want the database to be public, a really good security measure is just to keep it not public, so we can only access it from the server directly. Then we restart the SSH service for all these configurations to apply, and then we provide a little summary for ourselves. Important to note that
this user password, I typically just let this open SSL command set for me, so we need to save the details from that gets outputted so we can actually interact with the user when we log in. Okay, let's get this script onto the server, let's run it, see what it outputs, and then try and log in with our new admin user on the server.
All right, let's log into the server and actually run this setup script. So SSH, bleeding edge, edge, there we go. And then we create the script called SSH hardening. I'm gonna be using BI. So we copy paste what we have here, which is the script we just went through. What do we want to do?
For the purpose of this tutorial, I'm just gonna create a password called password. This is simply easier, but you should probably stick with this OpenSSL password. For the port, I'm just gonna create a random one here, 32, 40, 53, yeah, fine. Then I'm also gonna grab the public key here, and then paste it, there we go.
close that down. And that's it. So we create an admin of user called admin. The password is going to be password. The public key is set. The port is set. And we are ready to go. So we're going to say C mod plus X to make this script executable. And now we can say SSH a lot dot slash SSH dot
dot slash SSH underscore hardening dot SH and actually run the script. And we can see here that it takes in the values that we set. It then starts to run through the configuration. We need to save this password, but we pretty much can remember it. It goes through downloading the packages that we need. It sets the
the SSH config and add the UFF firewall rules and then it asks us to save all of this. So let's just grab this here. I'm gonna save this off screen. Then we say reboot. So we make sure all the changes are applied and we get kicked out. So just gonna give this a second to reboot and then we're gonna try to SSH in again to see if our changes actually worked. All right, let's
try an SSH in one more time. And nothing happens, which is what we hoped for. And one of the reasons why nothing happened is that we are still pointing towards port 22, which is no longer the SSH port. So if I go into my SSH config here and change this to the port we set up, which was 32.53 wide and crit. And again,
try it to SSH in, we see this permission denied. It's because we cannot lock in this route. So far, our setup is working. Let's actually change this to admin. And now try an SSH in. We get into the server. And now we have this isolated user that can access the server and perform the action we need as the admin. So if you do something like appetite,
Sorry, APT, not in Danish, but in English, APT update. We get permissions denied. What if we say is sudo? We need to provide the password, so that is password. And then we can perform the update action. So whenever we now need to perform administrative action, we need to provide a password so an extra layer of security if someone were to get access to the server.
You should also be able to say sudo as you use, so switch user to root. And now we are back in as root in the admin directory. And we've just run CD for change directory. We can see we are back in the root. And here we have our SSH hardening script that we just run. So we can still use root, but it needs to come through our admin user.
Now we're almost ready to add our application to the server and actually run it. But to do that, we're going to be needing a verbose proxy. We're going to be using something called catty. We also need to point a domain to this IP address of this server so we can have HTTPS be set up and access our block in a secure manner. And that's going to be the focus of the next episode.