Server Security

Category: Linux
Created: 2019-11-28
Updated: 2020-08-31

This document describes some “best practices” for improving security on a Linux server.


When installing a new server, you can improve the security of the server if you keep a few things in mind when partitioning:

  • Set up (at least) one separate partition for all user-writable directories. This is to prevent users from “filling up” the storage space (intentionally or unintentionally) and thus causing the server to fail.

    At least /var/www should be on its own partition. The mount option nodev and, if possible, noexec should be activated on this, and group quota should be enabled.

  • Create a separate partition for /tmp and enable the mount options nodev and nosetuid.

  • Optionally set the option noexec for the /tmp directory. This can reduce the risk of exploits a little.

    On Debian/Ubuntu based systems you should create a file /etc/apt/apt.conf.d/10noexec which contains the following lines:

    DPkg::Pre-Invoke { "mount -o remount,exec /tmp"; };
    DPkg::Post-Invoke { "mount -o remount /tmp"; };

Basic tasks

  1. limit access to MySQL/MariaDB

    The default installation of MySQL and MariaDB provides a database called test and allows anonymous access to that. Additionally, no initial password for the database admin account (root) is set.

    To fix this, run the script mysql_secure_installation:

    root@srv:~# mysql_secure_installation

    You will be asked several questions and will be prompted for a root password. You can usually answer all questions with its default value (yes).

  2. disable portmapper service

    Often the portmapper service is installed and enabled by default. When this service is available from outside, this is a security risk (the portmapper might be used by attackers for DDoS attacks).

    You can check if the portmapper is active with the tool rpcinfo:

    root@srv:~# rpcinfo
       program version netid     address                service    owner
        100000    4    tcp6      ::.0.111               portmapper superuser
        100000    3    tcp6      ::.0.111               portmapper superuser
        100000    4    udp6      ::.0.111               portmapper superuser
        100000    3    udp6      ::.0.111               portmapper superuser
        100000    4    tcp          portmapper superuser
        100000    3    tcp          portmapper superuser
        100000    2    tcp          portmapper superuser
        100000    4    udp          portmapper superuser
        100000    3    udp          portmapper superuser
        100000    2    udp          portmapper superuser
        100000    4    local     /var/run/rpcbind.sock  portmapper superuser
        100000    3    local     /var/run/rpcbind.sock  portmapper superuser

    In most cases you can not uninstall the portmapper service, because things like the quota subsystem depend on it. So just disable that service permanently:

    root@srv:~# systemctl stop rpcbind
    Warning: Stopping rpcbind.service, but it can still be activated by:
    root@srv:~# systemctl stop rpcbind.socket
    root@srv:~# systemctl disable rpcbind
    Removed symlink /etc/systemd/system/
  3. restrict access to su command

    Hosting users should never have access to the su command. We recommend to only allow members of the group adm to use the su command.

    1. add your admin users (non-root) to the adm group, e.g.:

      root@srv:~# usermod -aG adm admin-user
    2. add the following line to /etc/pam.d/su:

      auth   required group=adm
    3. test if executing su is now still possible for your admin user

    4. test whether “normal” users can’t run su any more

  4. restrict access to process list (ps)

    Normal users shouldn’t see which processes are running on the server (except of their own ones, of course). Restrict the access to the process list by adding hidepid=2 to the /proc entry in /etc/fstab:

    proc   /proc   proc   defaults,hidepid=2   0   0

    Then remount the /proc filesystem:

    root@srv:~# mount /proc -o remount

    All non-root users should now only see their own processes when running ps aux.

  5. restrict SSH access

    Access via SSH should also be restricted. Edit /etc/ssh/sshd_config and set these values:

    • PermitRootLogin no (or: PermitRootLogin without-password) to prevent brute-force password attacks on your root account (be sure to have created a normal admin account first, preferably with Public Key authentication!)
    • AllowTcpForwarding no and X11Forwarding no to not use your server as TCP tunnel into the internet
    • DebianBanner no (Debian/Ubuntu only) to not show your Debian/Ubuntu version before logging in (though the OpenSSH version is still displayed, which can hardly be suppressed)

    After that, restart the SSH daemon (service sshd restart).

    Many tutorials recommend to change the default port of SSH (port 22) to some random other port. Sorry, but this doesn’t help anything - in fact that’s even a security risk. Only applications with root privileges may bind to ports <1024. So if you decide to run SSH for example on port 12345, any user could easily run a program trying to bind to port 12345 by itself. On the next SSH restart this could be successful, and so a normal (unprivileged) user has hijacked your SSH access - which is at least a DoS. Either bind SSH to any port <1024, or better leave it at its default port.

sysctl tuning

The following tuning settings are based on the Kernel sysctl configuration file for Linux from Michiel Klaver.

Edit/create the file /etc/sysctl.d/security.conf (or download):

# Controls the System Request debugging functionality of the kernel
# Default: 438
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
# Default: 0
kernel.core_uses_pid = 1

# Allow for more PIDs
# Default: 32768
kernel.pid_max = 65535

# Controls the maximum size of a message, in bytes
# Default: 16384
kernel.msgmnb = 65535

# Controls the default maxmimum size of a mesage queue
# Default: 8192
kernel.msgmax = 65535

# Hide exposed kernel pointers
# Default: 0
kernel.kptr_restrict = 1

Edit/create the file /etc/sysctl.d/network-security.conf (or download):

# Prevent SYN attack, enable SYNcookies (they will kick-in when the max_syn_backlog reached)
# Default: tcp_syncookies=1, tcp_syn_retries=6, tcp_synack_retries=5, tcp_max_syn_backlog=1024
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096

# Disables IP source routing
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

# Enable IP spoofing protection, turn on source route verification
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable ICMP Redirect Acceptance
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# Enable Log Spoofed Packets, Source Routed Packets, Redirect Packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Enable a fix for RFC1337 - time-wait assassination hazards in TCP
net.ipv4.tcp_rfc1337 = 1

To apply your new settings, run the following command:

sysctl --system

This list is not exhaustive. If you have additional tips or comments, please contact us.