Safety on a New VPS

经验分享

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 ipv6 router discovery, neighbor-solicitation, etc
    ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big } accept
    
    # Allow ping(Optional)
    # ip protocol icmp accept
    # ip6 nexthdr icmpv6 accept

    # Allow SSH
    tcp dport 2015 accept
    
    # Allow HTTP/HTTPS traffic
    tcp dport 80 accept
    tcp dport 443 accept
    # If your site supports QUIC
    udp dport 443 accpept

}

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 ipv6 router discovery, neighbor-solicitation, etc
        ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big } accept
				
        # Allow ping(Optional)
        # ip protocol icmp accept
        # ip6 nexthdr icmpv6 accept

        # Allow SSH
        tcp dport 2015 accept
        
        # Allow HTTP/HTTPS traffic
        tcp dport 80 accept
        tcp dport 443 accept
        # If your site supports QUIC
        udp dport 443 accpept

    }
    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.

—————-我是分割线—————–

考虑到本博客的受众更多使用中文,所以还是再写一份中文版本。

新 VPS 的安全管理

不管是为了扩容服务、科学上网还是就是想屯,大家总会买新服务器~~(即使是完全不缺)~~。但是最近发现很多人部署服务的方式并不安全,有些甚至是在暴露更多的攻击面。所以就有了这篇文章,写一下拿到 VPS 之后的简单加固。

SSH 登录

这部分的调整需要更改 sshd 的配置,有一些点需要注意。如果你的 VPS 商家使用了 cloud-init 进行初始化(非常常见),就会有一个 50-cloud-init.conf 文件在 /etc/ssh/sshd_config.d 的路径下。如果这个文件包含了和 /etc/ssh/sshd_config 中相同的选项,则会覆盖这个选项,所以更好的(也是推荐的)方式是新建一个 00-custom.conf 文件在 /etc/ssh/sshd_config.d 路径下。前缀 “00” 表示他会以最高优先级加载并覆盖其他文件的所有相同关键字,即保证该文件的设置生效。

登录端口

默认情况下,SSH 连接使用 22 端口,但是使用这个端口容易吸引爆破攻击。把它改了是一个很常见的规避暴力攻击的方式。

00-custom.conf 文件中添加这样一行可以把端口改到 2025,当然你也可以使用任何没有被其他软件占用的端口。

Port 2025

不过需要注意的是,这只能减少一定自动化扫描和暴力破解的数量,并不能带来本质上的安全性提升。

身份验证

这是 SSH 安全最关键的部分。首先,我极其不推荐在任何暴露 SSH 端口在公网上的服务器只使用密码验证,而是使用密钥对进行登录。对于如何生成密钥对,可以参考 SSH Academy,中文教程可以参考 USTC LUG 101手册。要禁用密码登录,添加这样一行:

PasswordAuthentication no

其次,直接使用 root 账号登录也是不太安全的,万一哪天敲出来了 rm -rf / 就炸了, 但是维护服务器经常需要 root 权限,所以要不要用 root 登录自行决定吧。如果选择关掉 root 登录:

PermitRootLogin no

或者只禁用 root 的密码登录:

PermitRootLogin prohibit-password

但其实这不是必要的,如果你已经跟随第一步禁用了密码登录。

当然你也可以添加其他的组件来加固 SSH,比如使用 fail2ban 以及引入多因素认证(2FA)。

我比较推荐的配置如下:

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

sshd_config 其实有很多选项,感兴趣可以移步 man page

更改完配置之后,重启 ssh 服务:

# 用的是 Ubuntu/Debian 的话
sudo systemctl restart ssh

注意,一定要确认你能用新的 session 连上服务器之后再关闭现有连接!!

防火墙

如果你只是想过滤非法请求包,可以直接使用 ufw 来配置而不是使用 iptables 或者 nftales 这种路由表,ufw 会简单很多。

使用 ufw

确保你已经安装了它,如果没有的话就装一下:

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

默认情况下,ufw 会拒绝所有入站请求,允许所有出站请求,并拒绝所有路由请求(其实是 forwarding)。一般来说我们需要用 SSH 连接服务器,所以要添加相关规则:

# 注意!如果你跟随上个章节更改了 SSH 的端口号,这里也要改,
# 不然的话启动防火墙你就连不上服务器了
sudo ufw allow 2015/tcp

如果你有静态 IP 地址来访问这台服务器,你可以只允许白名单地址访问 SSH 端口。这样的话规则应该这样写:

sudo ufw allow from 12.34.56.78 proto tcp to any port 2015

如果你要提供网页服务(HTTP/HTTPS)或者其他什么服务,添加对应的规则:

sudo ufw allow 443
sudo ufw allow 80

添加完规则之后,可以检查一下:

sudo ufw status

如果看起来OK,那就可以启动了:

sudo ufw enable

使用 nftables

在新版本的 Ubuntu 和 Debian 中,nftables 是默认安装但不启用的,可以先修改规则再启动服务。nftables 默认使用 /etc/nftables.conf 中的配置,建议在修改前备份原始文件。

这个文件应该长这样:

#!/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;
    }
}

我们要允许 SSH 连接还有什么其他服务,并且丢弃所有乱七八糟的包,就可以在 input 链加上这些规则:

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

    # 本地环路得通
    iif "lo" accept

    # 允许已经建立的连接
    ct state established,related accept

    # 丢弃所有状态无效的包
    ct state invalid drop

    # 允许 ipv6 路由发现、邻居发现等协议
    ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big } accept
		
    # 允许 ping (可选)
    # ip protocol icmp accept
    # ip6 nexthdr icmpv6 accept

    # 允许 SSH
    tcp dport 2015 accept
    
    # 允许 HTTP/HTTPS
    tcp dport 80 accept
    tcp dport 443 accept
    # 如果你要支持 QUIC 的话
    udp dport 443 accept

}

如果你只想让特定 IP 访问 SSH,把规则改成:

tcp dport 2015 ip saddr { 12.34.56.78 } accept

这样的话,整个配置文件就成了:

#!/usr/sbin/nft -f

flush ruleset

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

        # 本地环路得通
        iif "lo" accept

        # 允许已经建立的连接
        ct state established,related accept

        # 丢弃所有状态无效的包
        ct state invalid drop

        # 允许 ipv6 路由发现、邻居发现等协议
        ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big } accept
        
        # 允许 ping (可选)
        # ip protocol icmp accept
        # ip6 nexthdr icmpv6 accept

        # 允许 SSH
        tcp dport 2015 accept

        # 允许 HTTP/HTTPS
        tcp dport 80 accept
        tcp dport 443 accept
        # 如果你要支持 QUIC 的话
        udp dport 443 accept
        
    }
    chain forward {
        type filter hook forward priority filter;
    }
    chain output {
        type filter hook output priority filter;
    }
}

编辑完文件之后,可以通过这条命令来检查是否存在语法错误:

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

如果没有输出,也就是没有错误,就可以启用服务了:

# 在 Ubuntu/Debian 上
sudo systemctl enable --now nftables

再次强调,一定要在这些更改后保证自己还能连上服务器再关闭现有的连接!

服务使用的权限

即使你为了方便选择使用 root 登录,直接使用 root 权限跑所有的服务也是不明智的,只要有一个服务被抓到了洞,整个 VPS 都危险了。有一个算是简单的方式,就是对不同的服务创建 shellnologin 的账户,然后启动时使用各自的用户,这样的话风险相对小一些。就比如网页服务器们,nginxApache 或者 Caddy,都是只用高权限启动父进程,处理请求都使用低权限(比如 www-data)的子进程。

并且,在 root 下执行脚本某种程度上是把 root 权限在这段时间给了脚本作者,所以这其实是高危行为。在你执行任何命令或者脚本前,确保你知道它是干什么的,尤其是在 root 权限下的时候。

发表回复

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

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