Safety on a New VPS

经验分享

We often need to buy servers for service scalability, bypassing The Firewall, or for various other reasons. However, I’ve noticed that many people are deploying services in an unsafe way, and some of their practices are actually exposing vulnerabilities to attackers. So here are some security tips you should keep in mind after booting up a new VPS.

SSH Login

We’re going to change the configuration of sshd, but there are a few things you should be aware of. If your VPS provider uses cloud-init (which is quite common), there will be a 50-cloud-init.conf file in the /etc/ssh/sshd_config.d directory. Files in this directory override the same options in /etc/ssh/sshd_config, so a better (and recommended) way to change the configuration is to create a 00-custom.conf file in /etc/ssh/sshd_config.d. The “00” prefix means this file will be loaded with the highest priority and will override the same settings in any other files.

Login Port

By default, port 22 is used for SSH connections, but keeping this port open attracts a lot of brute‑force attacks. Changing it to another port is a common practice to harden your server.

Adding the following line to the 00-custom.conf file will change the port to 2025. Of course, you can use any port that isn’t already in use by other software.

Port 2025

Keep in mind that this is not a real security measure; it only reduces noise from automated scans and brute‑force attempts.

Authentication

This is the most important part of SSH security. First of all, I strongly recommend not using password authentication for any server exposed to the Internet. Instead, you should use key pairs to log in to the server. For instructions on how to generate key pairs, you can refer to SSH Academy. To disable password logins, add the following line:

PasswordAuthentication no

Logging in directly as root is also not very safe — a single mistaken command like rm -rf / can be disastrous — but root privileges are often needed for maintenance. Whether you allow direct root login is up to you. You can choose to disable it:

PermitRootLogin no

or just disable password logins for root:

PermitRootLogin prohibit-password

However, this is actually not necessary, because we have already disabled password logins earlier.

You can always add more features to harden the server, such as fail2ban or two‑factor authentication (2FA).

The configuration I recommend is:

# /etc/ssh/sshd_config.d/00-custom.conf
Port 2025
PasswordAuthentication no
# Optional
# PermitRootLogin no

The whole options available could be found at man page.

After changing the configuration, restart the SSH service:

# If you are using Ubuntu/Debian
sudo systemctl restart ssh

Make sure you can connect to your server in a new session before closing the existing connection!

Firewall

For people who just want to drop unwanted packets and don’t need to manipulate traffic, you can simply use ufw instead of iptables or nftables. It’s quite simple.

Use ufw

Make sure you have it installed. If not, install it with:

# Ubuntu/Debian
sudo apt update && sudo apt install -y ufw

By default, ufw denies incoming packets, allows outgoing packets, and denies routed packets. Normally we need to connect to the server over SSH, so allow it by running:

# Note: If you changed the SSH port in the previous section,
# update the port number here, otherwise you will not be able to
# connect to the server.
sudo ufw allow 2015/tcp

If you use a static IP address to access your server, it’s safer to allow only whitelisted IPs to access the SSH port. In that case, the rule should look like this:

sudo ufw allow from 12.34.56.78 proto tcp to any port 2015

If your server is going to provide HTTP/HTTPS or any other services, add the corresponding rules:

sudo ufw allow 443
sudo ufw allow 80

After adding all the firewall rules, you can check them at any time with:

sudo ufw status

If everything looks good, you can enable it now:

sudo ufw enable

Use nftables

On recent versions of Ubuntu and Debian, nftables is installed but not enabled by default, and you can edit the rules before enabling it. nftables uses /etc/nftables.conf by default. Remember to back it up before editing, just in case.

The file should look like this:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority filter;
    }
    chain forward {
        type filter hook forward priority filter;
    }
    chain output {
        type filter hook output priority filter;
    }
}

Now we want to allow SSH connections and some other services while denying all unexpected packets, so add the rules in the input chain:

chain input {
    type filter hook input priority filter; policy drop;

    # allow local loop
    iif "lo" accept

    # allow established connections
    ct state established,related accept

    # drop all invalid packages
    ct state invalid drop

    # Allow ping(Optional)
    # ip protocol icmp accept
    # ip6 nexthdr icmpv6 accept

    # Allow SSH
    tcp dport 2015 accept

}

If you only want a specific IP to access SSH, change the rule to:

tcp dport 2015 ip saddr { 12.34.56.78 } accept

Then the whole configuration file should look like this:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority filter; policy drop;

        # allow local loop
        iif "lo" accept

        # allow established connections
        ct state established,related accept

        # drop all invalid packages
        ct state invalid drop

        # Allow ping(Optional)
        # ip protocol icmp accept
        # ip6 nexthdr icmpv6 accept

        # Allow SSH
        tcp dport 2015 accept

    }
    chain forward {
        type filter hook forward priority filter;
    }
    chain output {
        type filter hook output priority filter;
    }
}

After editing the configuration, check it with:

sudo nft --check -f /etc/nftables.conf

If there’s no output, it means there are no errors, and you can enable it by running:

# On Ubuntu/Debian
sudo systemctl enable --now nftables

Again, you should always check that you can still connect to the server before closing existing connections.

Service Permissions

Even if you keep using the root account for more convenient maintenance, it’s not wise to run all services with root privileges, because if a single service is compromised, the entire VPS will be at risk. A simple approach is to create separate accounts with nologin shells to run different applications. When running web servers like nginx, Apache, or Caddy, you’ll notice that they only launch the parent process with elevated privileges and use child processes running under accounts like www-data to handle requests.

Also, running a script as root means you are effectively giving the author root privileges for that period of time. Make sure you know what it does before executing any command or script, especially when using the root account.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理