Here is a quick and by no means comprehensive guide on the very basics of securing a Linux server. This article is mostly targeted towards users with small infrastructures and does not properly accommodate cloud users. Regardless many of the practices and concepts within this article hold true and can be applied to various systems.
The absolute minimum
Don't set your admin login to something that can be found on a word list.
If you have to use a web based admin panel I recommend setting it to something that will not be found by a typical dirb scan. Be creative but also remember that this should not be your primary line of defense.
Use a strong password or setup SSH keys.
This one is so obvious so just make sure that your password meets the following criteria:
- Includes uppercase, lowercase, numbers, symbols.
- Is at least 16 digits long.
- Isn't found in a wordlist.
- Isn't used on any of your other accounts.
If you rather avoid passwords entirely you can opt for using SSH keys instead which essentially allows you to completely bypass password authentication as long as you have the proper keys on your system. This is not required and if you follow the steps above for setting up a secure password then this shouldn't provide any substantial security over the other. The argument that passwords can be brute forced and keys cannot is very weak. The only viable method for brute forcing ssh remotely is by using a predefined wordlist such as rockyou. For the sake of simplicity let's say we wanted to brute force a 16 digit alphanumeric password. The amount of possible permutations for that password can be described by the following equation (26+26+10)^16 which evaluates to 4.767240170682353e+28. Anybody that unironically thinks they can brute force that many permutations remotely is retarded and doesn't know what they're talking about. So yeah use keys if you want but strong passwords that are truly unique provide about the same amount of security.
Limit the amount of services you use.
One of the most important and basic things you want to do is to limit your exposure and reduce your server's attack surface. To elaborate, make sure that every single service or program running on your server is essential. If there are processes that you don't recognize, do some research and decide if the process is essential or even supposed to be there. This is increasingly important for internet facing services such as an unconfigured webserver.
Use better alternatives.
Always try to deploy the best tool for the job, ie: SSH instead of telnet, SFTP over FTP, newest TLS over SSL.
Ensure your server is frequently updated, critical patches should be deployed within hours of their release.
Set proper permissions
Make sure file and directory permissions are set in a way so that if a service is compromised it wont be able to easily modify configs that would compromise other services within the server.
These steps may seem obvious step but security is only as strong as it's weakest link, and these basic failures are actually frequently responsible for a server being compromised.
Software firewalls are something that I deeply recommend to setup so that only certain types of requests are able to actually interact with services on your server. You can think of a firewall as a condom, sure it ruins the fun but at least they stop some of the tinier threats.
In this article I'm going to be talking about 2 options that I think are pretty decent for starters and intermediate users. If you're a noob you can use UFW, which is a pretty comprehensive and easy to use iptables wrapper that does the job. But if you're a real one than you can skip the middle man and jump into iptables. Lucky for you guys I already made a list of some good iptables rules for most server. Just make sure to enter these commands in the exact order they're listed in as it does make a difference.
#Drop invalid packets iptables -A INPUT -m conntrack --ctstate INVALID -j DROP # Allow existing sessions iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow web, ssh iptables -A INPUT -p tcp --match multiport --dports 80,443,22 -j ACCEPT # Allow loopback connections iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # Drop everything else iptables -A INPUT -j DROP
UFW Rules (baby version)
# Allows traffic through TCP ports 80, 443, and 22. $ ufw allow 80/tcp $ ufw allow 443/tcp $ ufw allow 22/tcp # Enables, reloads, and checks the status of UFW. $ ufw enable $ ufw reload $ ufw status
If you use ssh, then the following may be useful to you. Add the following to your /etc/ssh/sshd_config file and restart the ssh daemon.
LoginGraceTime 1m # This option specifies how much time a user has to login before the request is dropped. Port # Trust me if you check your ssh logs you'll see literally thousands of failed authentication attempts from China alone daily. Believe it or not changing the default ssh port is actually a decent fix, I recommend setting it to a higher number that is uncommon so that port scanners won't detect it unless they scan all ports sequentially (which is even more of a pain in the ass if you have a firewall that ratelimits port scanners). PermitRootLogin no # This is optional and should be enabled if you don't want users to be able to remotely log into root. AllowUsers waffles # Use this setting to create a whitelist of users allowed to login DenyUsers web mail v01dwalk # Use this setting if you have users for certain services and don't want somebody to be able to log into them
The following are a few kernel flags that I believe merit attention...
In order to set the following kernel flags copy and paste the code block below into your /etc/sysctl.conf file or optionally create a file within /etc/sysctl.d/ and paste the following within it.
Enables ASLR (address space layout randomization). The main purpose of ASLR is to randomize memory segments to make abuse by malicious programs more difficult. This should hopefully be enabled by default on your distro.
kernel.randomize_va_space = 2
Disables your servers response to ping requests and ICMP broadcasts.
net.ipv4.icmp_echo_ignore_all = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1
Disable IPv6, this is not realistic for everyone, but if your services don't require the usage of IPv6 then it might be advantageous to disable it entirely.
net.ipv6.conf.all.disable_ipv6 = 1
Cron jobs are automated tasks that are ran on a pre-set interval. I use them for a few things such as automating backups, cert renewal, and deleting old logs. Note that for deleting old logs it's generally recommended to use logrotate instead. Logrotate is usually pre-installed on most distros and has built in functionality for deleting logs that expire past a certain deadline.
To set cron jobs run crontab -e and place the following within the file:
## Backup up files on every 9th day of the month # /var/www 0 0 9,18,27 * * tar -zcf /var/backups/www/$(date +"\%m-\%d-\%Y").tgz /www # /user 0 0 9,18,27 * * tar -zcf /var/backups/user/$(date +"\%m-\%d-\%Y").tgz /user #/etc 0 0 9,18,27 * * tar -zcf /var/backups/etc/$(date +"\%m-\%d-\%Y").tgz /etc ## Delete old log and backup files 0 0 9,18,27 * * find /var/log -mtime +30 -print -delete 0 0 9,18,27 * * find /var/backups -mtime +45 -print -delete
All though this leans more towards bigger infrastructures and compliance, it's definitely not a bad idea to setup an auditing platform for your server so that your systems processes, binaries, packages, and all other vitals are monitored. Auditing software is especially useful at detecting changes to binaries such as ps or ls which are sometimes replaced with altered version which would intentionally hide certain files or processes. I'm actually in the process of developing my own CLI based auditing solution for my own servers as the current solutions are always missing something.
1. Configure your webserver to run with a lower user and group permissions and restrict it's permissions to only it's log folder and the actual content it has to serve.
2. If you want to screw with some lesser URL fuzzers create an endless redirect loop whenever a request matches a certain pattern. For example if somebody sends a requests to /admin, redirect them to /loop and have /loop redirect to /admin. It's a pretty simple yet effective way and you can really be creative with the sheer ambiguity.
Since it's inception DNS has been an unencrypted protocol which unfortunately allows for man in the middle attacks (MITM). MITM attacks allow others to intercept your traffic, in the case of DNS it allows others to see which websites you're visiting. DNS over HTTPS (DoH) allows you to encrypt DNS traffic which is quite nice. In order to enable DoH on systems with systemd installed you can do the following:
Edit both /etc/resolv.conf and /etc/systemd/resolved.conf, then add the following lines to each file. Note sometimes NetworkManager overwrites these files.
[Resolve] DNS=18.104.22.168 FallbackDNS=22.214.171.124 DNSSEC=yes DNSOverTLS=yes #MulticastDNS=yes #LLMNR=yes #Cache=yes #DNSStubListener=yes #ReadEtcHosts=yes #ResolveUnicastSingleLabel=no
Next restart the systemd-resolved service and check it's status.
sudo systemctl restart systemd-resolved.service sudo systemctl status systemd-resolved.service
If all is well you can double check that everything is working by visiting https://www.cloudflare.com/ssl/encrypted-sni/ in your browser.
I'm sure that there are things I could have explained better or even items that I completely missed. I want this article to improve with time so if you want to make suggestions reach out to me via my discord server and we can discuss how to improve this article. Finally I just thought I'd mention that I left out SElinux and few other things intentionally as I believe they merit their own post all together.