A freshly bought VPS is like an unlocked door with script kiddies knocking from all over the world. This guide walks you through locking that door tight, so your openclaw won’t go running wild.

0. Before We Begin

You just bought a VPS, excitedly grabbed the IP and root password, and now what?

Most folks just dive right in: installing software and deploying their projects.

That’s a dangerous habit.

Your VPS has a public IP, meaning anyone in the world can try to connect to it. And with the default setup:

  • Port 22 is open to the public
  • The username is the universally known root
  • Leaving just a single password to protect you

Countless automated scripts are scanning IP ranges every single day, brute-forcing common passwords. The moment your server goes live, it’s already under attack.

So, the very first thing you do after getting a VPS isn’t installing software—it’s locking down security.


1. Our Goal

The goal of this guide is:

  • ✅ Set up secure remote access: SSH key login + a non-default port
  • ✅ Create a standard user: avoid using root directly
  • ✅ Configure a firewall: only open the ports you actually need
  • ✅ Enable network acceleration: let BBR make your network fly
  • ✅ Prevent brute-force attacks: fail2ban auto-bans malicious IPs

Once you’ve done all this, your VPS will have a rock-solid foundation, and you can deploy all sorts of services on it with total peace of mind.


2. Planning & Thinking

Why bother with all these configurations?

A freshly bought VPS is a lot like a brand-new unfinished house:

Default State Risk Our Solution
Logging in directly as root Too much privilege, high risk of accidental damage Create a standard user + sudo
Password login Vulnerable to brute-force attacks SSH key authentication
Default port 22 Prime target for port scanners Switch to a non-standard port
Firewall disabled All ports exposed to the internet UFW: only allow essential ports
Native network High packet loss, high latency BBR congestion control algorithm

The Overall Workflow

VPS初始化流程

We’ll follow this exact order, and I’ll explain the “why” behind each step as we go.

3. Step-by-Step Guide

3.1 First Login & System Update

Grab Your Server IP

Once you’ve bought your VPS, your provider will give you:

  • IP address: like 192.168.1.100
  • Port: usually 22 (some providers might change it to a different port)
  • Username: usually root
  • Password: a randomly generated string

VPS 服务商后台的登录信息页面

SSH Connection

Mac / Linux users: open your terminal and just type:

1
2
ssh root@你的服务器IP
# 例如:ssh [email protected]

Windows users:

  • Windows 10/11 comes with OpenSSH built-in, so you can run the command above directly in PowerShell or CMD
  • Or you can use tools like Termius, MobaXterm

The first time you connect, you’ll see a fingerprint confirmation prompt:

1
2
3
The authenticity of host '192.168.1.100 (192.168.1.100)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

It’s basically asking: “I don’t recognize this machine, are you sure you want to connect?”

Type yes and hit Enter. Then enter your password (note: no characters will show up as you type, this is a normal security feature) and hit Enter.

首次 SSH 连接的完整过程,包含指纹确认

If you see a prompt like this, you’re successfully logged in:

1
2
3
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.x.x-x-generic x86_64)
...
root@hostname:~#

💡 Why verify the fingerprint?

This is to prevent “man-in-the-middle” (MITM) attacks. By saving the server’s fingerprint on your first connection, you’ll know something’s up if it ever changes down the road—usually a sign someone might be spoofing your server.

登录成功了

Getting to know your server

Once you’re logged in, let’s take a quick look at what this machine is packing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看系统版本
cat /etc/os-release

# 查看内核版本
uname -r

# 查看 CPU 核心数和型号
nproc
lscpu | grep "Model name"

# 查看内存
free -h

# 查看磁盘
df -h

服务器基本信息输出

Keep these details in mind—they’ll come in handy when troubleshooting later on.

System update

Alright, now that we’ve scoped out the server specs, the first real order of business is updating the system. Fresh server images can be a few months old, and there might be critical security patches waiting for you:

1
2
# 更新软件包列表 + 升级所有软件 + 清理
apt update && apt full-upgrade -y && apt autoremove -y && apt autoclean

Here’s what those flags do:

  • apt update: Updates the package index
  • apt full-upgrade: Upgrades all installed packages, including the kernel
  • -y: Automatically says “yes” to prompts so you don’t have to babysit it
  • apt autoremove: Cleans up dependencies that are no longer needed
  • apt autoclean: Clears out the cached downloaded package files

apt update 和 apt upgrade 执行过程

⏱️ This step might take a few minutes, depending on how many updates are queued up. If it occasionally stops to ask for confirmation, just follow the prompts and you’ll be fine.

Checking if a reboot is needed

After a kernel update, you’ll usually need to reboot for it to take effect:

1
2
# 检查是否需要重启
cat /var/run/reboot-required 2>/dev/null && echo ">>> 需要重启" || echo ">>> 无需重启"

是否需要重启

If it tells you a reboot is required:

1
reboot

Once it reboots, you’ll need to SSH back in.

Installing essential tools

1
apt install -y sudo curl wget git vim htop tree unzip net-tools ufw fail2ban neofetch

What these tools are for:

Tool What it’s for
sudo Lets regular users run admin commands
curl / wget Download files
git Version control
vim Text editor
htop A prettier process monitor
tree Show directory structure as a tree
net-tools Network tools (ifconfig, netstat, etc)
ufw Simple and easy firewall
fail2ban Brute-force protection
neofetch Display system info beautifully
neofetch 显示的系统信息

3.2 Creating a Non-Root User

Why not just use root?

The root user has way too much power. One typo with rm -rf / and everything is gone. For your daily operations, you should stick to a regular user and only use sudo when you actually need admin privileges.

The openclaw is a monster—would you really dare to hand root privileges over to it?

Creating the User

1
2
# 创建用户(把 ittinker 换成你想要的用户名)
adduser ittinker

The system will prompt you to set a password and fill in some basic info:

1
2
3
4
5
6
7
8
New password:              # 输入密码(不会显示)
Retype new password: # 再输入一次
Full Name []: # 可以直接回车跳过
Room Number []: # 回车跳过
Work Phone []: # 回车跳过
Home Phone []: # 回车跳过
Other []: # 回车跳过
Is the information correct? [Y/n] # 输入 Y 确认

adduser 创建用户的完整交互过程

Granting sudo Privileges

1
2
# 把用户加入 sudo 组, ittinker 换成你自己上面创建的那个用户
usermod -aG sudo ittinker

Let’s verify it:

1
2
3
4
5
# 切换到新用户 ittinker 换成你自己上面创建的那个用户
su - ittinker

# 测试 sudo 是否生效
sudo whoami

If the output shows root, your sudo setup is good to go.
测试sudo

💡 Pro Tip

Type exit to switch back to the root user. We’ll keep using root for the rest of the setup, and once everything is configured, we’ll switch back to the regular user.


3.3 Setting Up SSH Key Authentication

Key Authentication vs. Password Authentication

SSH密钥认证原理

Key authentication is way more secure than passwords:

  • Passwords can be brute-forced; keys are practically impossible to crack
  • No need to type your password every time—much more convenient
  • Even if your password leaks, no one can log in without the private key

Step 1: Generate a Key Pair Locally

Run this on your local machine (not the server):

1
2
# 生成 ED25519 密钥(推荐,更安全更快)
ssh-keygen -t ed25519 -C "[email protected]"

You’ll be prompted with:

1
Enter file in which to save the key (/Users/你/.ssh/id_ed25519):

Just hit Enter to accept the default path. Here we’re using ./ittinker, which simply means it’ll be saved in your current directory with the filename ittinker.

1
Enter passphrase (empty for no passphrase):

You can set a passphrase for the key (an extra layer of protection), or just hit Enter to leave it blank.

本地生成 SSH 密钥的过程

Once it’s done generating, you’ll see two files in the ~/.ssh/ directory (these are the default filenames you’ll get if you just hit Enter earlier):

  • id_ed25519: Your private key. Keep this absolutely safe and never leak it!
  • id_ed25519.pub: Your public key. This is the one you’ll upload to the server.

💡 ed25519 vs RSA

ed25519 is the currently recommended algorithm—it’s more secure and has a shorter key than traditional RSA. If your system is too old and doesn’t support it, you can fall back to ssh-keygen -t rsa -b 4096.

A quick side note: ed25519 generates a much smaller key file, whereas RSA files are pretty bulky. I actually asked an AI about this—turns out the file size doesn’t really matter, it’s just how the algorithms work.

Step 2: Upload Your Public Key to the Server

Method A: Using ssh-copy-id (Recommended)

1
2
# 在你的电脑上执行
ssh-copy-id -i ~/.ssh/id_ed25519.pub yourname@你的服务器IP

After typing in your password, your public key will be automatically copied over to the server.

ssh-copy-id 执行成功

Method B: Manual Copy

If ssh-copy-id doesn’t work, you can just do it manually:

1
2
# 1. 在你的电脑上,查看公钥内容
cat ~/.ssh/id_ed25519.pub

Copy the output (that long string of text starting with ssh-ed25519).

1
2
3
4
5
6
7
8
9
10
11
# 2. 在服务器上,为新用户创建 .ssh 目录, ittinker 换成你刚刚创建的用户名
mkdir -p /home/ittinker/.ssh
chmod 700 /home/ittinker/.ssh

# 3. 创建 authorized_keys 文件并粘贴公钥
vim /home/ittinker/.ssh/authorized_keys
# 按 i 进入编辑模式,粘贴公钥,按 Esc,输入 :wq 保存退出

# 4. 设置正确的权限
chmod 600 /home/ittinker/.ssh/authorized_keys
chown -R ittinker:ittinker /home/ittinker/.ssh

⚠️ Permissions are crucial!

SSH is super strict about file permissions:

  • .ssh directory: 700 (only you can access it)
  • authorized_keys file: 600 (only you can read and write to it)

If the permissions are off, SSH will refuse to use the key for login.

Step 3: Test your key-based login

Open a new terminal window (keep the original one open just in case you mess up and need a backup), and test the key login:

1
ssh ittinker@你的服务器IP

If you can log in without typing a password, your key setup is successful! 🎉

(If you set a passphrase for your private key, it’ll prompt you for that private key password—which is totally normal.)
使用密钥成功登录(无需服务器密码)

We added the -i flag here because our key isn’t in the default path. We put it in the current directory instead. If you don’t specify it, the system will just try to use the default key.


3.4 Hardening SSH Security

Now that key-based login is up and running, let’s lock down SSH:

  1. Change the default port (to dodge automated port scans)
  2. Disable password authentication
  3. Block direct root login

Edit the SSH config file

1
2
3
4
5
# 备份原配置
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

# 编辑配置
nano /etc/ssh/sshd_config

修改前

Find and tweak the following settings (some might be commented out, so just remove the leading #):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 修改端口(选一个 1024-65535 之间的数字)
Port 22000

# 禁止 root 登录
PermitRootLogin no

# 允许密钥登录
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# 禁止密码登录(确保密钥登录测试成功后再改!)
PasswordAuthentication no

# 使用更安全的 SSH2 协议
Protocol 2

# 最大认证尝试次数
MaxAuthTries 3

# 客户端超时设置
ClientAliveInterval 300
ClientAliveCountMax 2

修改后的 sshd_config 关键配置

Save and exit (ctrl + o).

In Nano, you save by hitting ctrl + o. It’ll prompt you for the filename—just press Enter to confirm. To quit, hit ctrl + x.

Restart the SSH service

1
systemctl restart sshd.service

⚠️ Heads up!

Don’t close your current terminal just yet! First, open a new window and test if you can log in with the new setup:

1
ssh -p 22000 yourname@你的服务器IP

If it works, you’re good to close the old window. If you can’t log in, you can still fix the config from your original session.

If you bought a lightweight server, chances are you can’t change this port. Traditional ECS instances usually let you modify it, so just keep that in mind.


3.5 Set up the UFW firewall

UFW防火墙规则

UFW (Uncomplicated Firewall) is Ubuntu’s default firewall tool. It’s super simple to configure but packs a punch.

Basic setup

1
2
3
4
5
6
7
8
9
10
11
# 设置默认策略:拒绝所有入站,允许所有出站
ufw default deny incoming
ufw default allow outgoing

# 允许 SSH(使用你设置的端口)
ufw allow 22000/tcp comment 'SSH'
ufw allow 22/tcp comment 'SSH' # 如果是轻量服务器,还是开22端口

# 允许 HTTP 和 HTTPS
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'

Enable the firewall

1
ufw enable

It’ll prompt you:

1
Command may disrupt existing ssh connections. Proceed with operation (y|n)?

Type y to confirm.

Check the status

1
ufw status verbose

ufw status 的输出结果

23022 was a typo on my end—just swap in whatever works for your own setup.

Output looks like:

1
2
3
4
5
6
7
8
9
10
11
12
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)

To Action From
-- ------ ----
22000/tcp (SSH) ALLOW IN Anywhere
80/tcp (HTTP) ALLOW IN Anywhere
443/tcp (HTTPS) ALLOW IN Anywhere
22000/tcp (SSH (v6)) ALLOW IN Anywhere (v6)
80/tcp (HTTP (v6)) ALLOW IN Anywhere (v6)
443/tcp (HTTPS (v6)) ALLOW IN Anywhere (v6)

Common Commands Cheat Sheet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看状态
ufw status

# 添加规则
ufw allow 8080/tcp

# 删除规则
ufw delete allow 8080/tcp

# 允许特定 IP 访问所有端口
ufw allow from 192.168.1.100

# 禁用防火墙(不推荐)
ufw disable

# 重置所有规则
ufw reset

3.6 Enabling BBR Acceleration

BBR (Bottleneck Bandwidth and Round-trip propagation time) is a TCP congestion control algorithm developed by Google that can significantly boost your network performance.

One-Click Enable

1
2
3
4
5
6
# 添加 BBR 配置
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf

# 使配置生效
sysctl -p

Verify It’s Enabled

1
2
# 查看当前拥塞控制算法
sysctl net.ipv4.tcp_congestion_control

Output should be:

1
net.ipv4.tcp_congestion_control = bbr
1
2
# 确认 BBR 模块已加载
lsmod | grep bbr

Output looks like:

1
tcp_bbr    20480  3

💡 What BBR Does

Once BBR is up and running, especially on unstable networks or high-latency connections, you’ll noticeably feel:

  • Faster download speeds
  • Smoother SSH sessions
  • Quicker webpage loading

bbr 开启


3.7 Setting Up fail2ban to Prevent Brute-Force Attacks

fail2ban monitors your logs and automatically bans any IPs that rack up too many failed login attempts.

Basic Configuration

1
2
3
4
5
# 复制默认配置(不要直接修改 jail.conf)
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# 编辑配置
vim /etc/fail2ban/jail.local

Find the [sshd] section and make sure the following settings are in place:

1
2
3
4
5
6
7
8
[sshd]
enabled = true
port = 22000 # 改成你的 SSH 端口
filter = sshd
logpath = /var/log/auth.log
maxretry = 3 # 最大尝试次数
bantime = 3600 # 封禁时间(秒),这里是 1 小时
findtime = 600 # 在这个时间窗口内

fail2ban

Start the service

1
2
3
4
5
# 重启 fail2ban
systemctl restart fail2ban

# 设置开机自启
systemctl enable fail2ban

Check the status

1
2
3
4
5
# 查看 fail2ban 状态
fail2ban-client status

# 查看 SSH 监控状态
fail2ban-client status sshd

fail2ban-client status sshd 的输出

The output will look something like this:

1
2
3
4
5
6
7
8
9
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:

Common commands

1
2
3
4
5
6
7
8
# 手动封禁 IP
fail2ban-client set sshd banip 1.2.3.4

# 手动解封 IP
fail2ban-client set sshd unbanip 1.2.3.4

# 查看被封禁的 IP
fail2ban-client status sshd

3.8 [Optional] Managing Multiple Servers with SSH Config

If you’re juggling multiple servers, typing out ssh -p 22000 user@ip every single time gets old fast. You can use SSH Config to make your life a lot easier.

The Config File

Edit ~/.ssh/config on your local machine:

1
vim ~/.ssh/config

Add your configurations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 第一台服务器
Host vps1
HostName 192.168.1.100
User yourname
Port 22000
IdentityFile ~/.ssh/id_ed25519

# 第二台服务器
Host vps2
HostName 192.168.1.101
User admin
Port 22222
IdentityFile ~/.ssh/id_ed25519

# 通用设置(应用于所有连接)
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes

How to Use It

Now you can connect directly using an alias:

1
2
3
4
5
# 连接第一台服务器
ssh vps1

# 连接第二台服务器
ssh vps2

No more memorizing IPs, ports, and usernames!


3.9 [Optional] Restrict Access to Cloudflare Only

If your site sits entirely behind Cloudflare, you can lock down ports 80 and 443 so only Cloudflare’s IPs can reach them. It’s a great little security boost.

⚠️ Heads up: This setup requires your domain to already be proxied through the Cloudflare CDN.

Auto-Configuration Script

1
2
3
4
5
6
7
8
# 下载脚本
wget -O ~/.cloudflare-ufw.sh https://gist.githubusercontent.com/Xm798/12560579ce11f62027ea8da1fae37456/raw/b07ac8cfe09badf02fc70e2d8bc2da68cabbda50/cloudflare-ufw.sh

# 添加执行权限
chmod +x ~/.cloudflare-ufw.sh

# 执行脚本
~/.cloudflare-ufw.sh

This script will:

  1. Grab the latest IP ranges straight from Cloudflare
  2. Add UFW rules to only allow those IPs to hit ports 80/443
  3. Reload UFW

Set Up Scheduled Updates

Cloudflare’s IP ranges can change over time, so let’s set this to auto-update every week:

1
2
# 添加 cron 任务(每周一凌晨执行)
(crontab -l 2>/dev/null; echo "0 0 * * 1 /root/.cloudflare-ufw.sh > /dev/null 2>&1") | crontab -

3.10 Set Your Timezone

The default timezone is probably UTC. Let’s switch it to your local timezone so reading logs is a breeze:

1
2
3
4
5
6
7
8
# 查看当前时区
timedatectl

# 设置为上海时区(中国用户)
sudo timedatectl set-timezone Asia/Shanghai

# 验证
date

设置时区


3.11 [Optional] Set Up Automatic Security Updates

Let the system install security patches automatically so you don’t have to do it manually every time:

1
2
3
4
5
# 安装自动更新工具
sudo apt install -y unattended-upgrades

# 配置
sudo dpkg-reconfigure --priority=low unattended-upgrades

Select “Yes” to enable automatic updates.

💡 This will automatically install security updates only. It won’t upgrade your system to a major new release, so it’s pretty safe to leave on.


4. Wrap Up

Post-Setup Checklist

Once you’ve got all the above configured, run through this checklist to double-check everything:

Check Command Expected Result
System is up to date apt update && apt list --upgradable No packages to upgrade
Regular user can sudo sudo whoami Outputs root
Key-based login works ssh yourname@ip -p port Logs in without a password
Password login is disabled grep PasswordAuth /etc/ssh/sshd_config PasswordAuthentication no
SSH port changed grep Port /etc/ssh/sshd_config The port you set
Firewall is enabled ufw status Status: active
BBR is enabled sysctl net.ipv4.tcp_congestion_control = bbr
fail2ban is running systemctl status fail2ban active (running)
Timezone is set timedatectl Asia/Shanghai or your timezone
Local SSH Config cat ~/.ssh/config Server alias configured

Key File Locations

1
2
3
4
/etc/ssh/sshd_config        # SSH 服务端配置
~/.ssh/authorized_keys # 允许登录的公钥
~/.ssh/config # 本地 SSH 客户端配置(在你电脑上)
/etc/fail2ban/jail.local # fail2ban 配置

Security Best Practices

  1. Update your system regularly: apt update && apt upgrade
  2. Check login logs regularly: lastb (failed logins), last (successful logins)
  3. Keep an eye on fail2ban bans
  4. Back up important config files before making changes

5. Troubleshooting

Q1: Key-based login failed, still asking for a password?

Possible reasons:

  1. Permission issues (most common)

    1
    2
    3
    # 检查并修复权限
    chmod 700 ~/.ssh
    chmod 600 ~/.ssh/authorized_keys
  2. Public key wasn’t copied correctly

    1
    2
    3
    # 检查 authorized_keys 内容
    cat ~/.ssh/authorized_keys
    # 应该是一行完整的公钥,以 ssh-ed25519 或 ssh-rsa 开头
  3. SELinux interference (on CentOS/RHEL systems)

    1
    restorecon -Rv ~/.ssh

Q2: Can’t connect after changing the port?

Troubleshooting steps:

  1. Make sure the new port is open in your firewall:

    1
    ufw status | grep 你的端口
  2. Double-check your SSH config:

    1
    grep Port /etc/ssh/sshd_config
  3. Verify the SSH service is actually running:

    1
    systemctl status sshd
  4. If you’re completely locked out, use your cloud provider’s VNC or web console to log in and fix it.

Q2.5: Port change not taking effect at all? (On lightweight cloud servers)

Symptom: You changed /etc/ssh/sshd_config, but after restarting the service, port 22 is still listening and the new port isn’t working.

How to diagnose it:

bash

1
2
# 查看是谁在监听 22 端口
netstat -lntp | grep :22

If the output looks something like this:

1
tcp  0  0.0.0.0:22  0.0.0.0:*  LISTEN  1/init

It means port 22 is being listened on by init (PID 1), not the sshd process.

Why?: Some cloud providers’ “Lightweight Servers” or “Container Instances” proxy SSH at the platform layer, meaning your server’s internal sshd config won’t take effect at all.

The Fix:

Instance Type How to Change SSH Port
Traditional ECS Edit sshd_config ✅
Lightweight Server Might need to be changed in the cloud console, or not supported at all
Container Instance Usually not supported

If your instance doesn’t support changing the port, other security measures become even more critical:

  • ✅ Create a standard user + disable root login
  • ✅ Use SSH key authentication + disable password login
  • ✅ Use fail2ban to block brute-force attacks

Nail these down, and your server will still be highly secure.

Q3: fail2ban banned me by mistake?

1
2
3
4
5
# 用 VNC 登录后解封
fail2ban-client set sshd unbanip 你的IP

# 把你的 IP 加入白名单,编辑 jail.local
ignoreip = 127.0.0.1/8 ::1 你的IP

Q4: Website inaccessible after enabling UFW?

1
2
3
4
5
6
# 检查 80/443 是否开放
ufw status

# 如果没有,添加规则
ufw allow 80/tcp
ufw allow 443/tcp

Q5: “sudo: command not found” when running commands?

A minimal Debian install might not come with sudo. Install it using root:

1
2
apt install sudo
usermod -aG sudo ittinker

6. One-Click Init Script (For When You’re Comfortable)

Once you’re familiar with the steps above, you can use this script to fast-track the setup.

⚠️ Heads up: Before running the script, make sure you’ve already got your SSH public key ready.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/bin/bash
# VPS 初始化脚本
# 使用方法:以 root 身份运行

set -e

# === 配置区域(根据你的需求修改)===
NEW_USER="ittinker" # 新用户名
NEW_SSH_PORT="22000" # 新 SSH 端口
TIMEZONE="Asia/Shanghai" # 时区
# =====================================

echo "=== VPS 初始化脚本 ==="
echo ""

# 1. 更新系统
echo "[1/8] 更新系统..."
apt update && apt upgrade -y

# 2. 安装基础工具
echo "[2/8] 安装基础工具..."
apt install -y sudo curl wget git vim htop tree unzip net-tools ufw fail2ban neofetch

# 3. 创建新用户
echo "[3/8] 创建用户 $NEW_USER..."
if id "$NEW_USER" &>/dev/null; then
echo "用户已存在,跳过创建"
else
adduser --gecos "" $NEW_USER
usermod -aG sudo $NEW_USER
fi

# 4. 配置 SSH 目录
echo "[4/8] 配置 SSH 目录..."
mkdir -p /home/$NEW_USER/.ssh
chmod 700 /home/$NEW_USER/.ssh
touch /home/$NEW_USER/.ssh/authorized_keys
chmod 600 /home/$NEW_USER/.ssh/authorized_keys
chown -R $NEW_USER:$NEW_USER /home/$NEW_USER/.ssh

echo ""
echo ">>> 请将你的公钥粘贴到下面(粘贴后按 Ctrl+D 结束):"
cat >> /home/$NEW_USER/.ssh/authorized_keys
echo ""

# 5. 修改 SSH 配置
echo "[5/8] 修改 SSH 配置..."
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sed -i "s/^#*Port .*/Port $NEW_SSH_PORT/" /etc/ssh/sshd_config
sed -i "s/^#*PermitRootLogin .*/PermitRootLogin no/" /etc/ssh/sshd_config
sed -i "s/^#*PasswordAuthentication .*/PasswordAuthentication no/" /etc/ssh/sshd_config
sed -i "s/^#*PermitEmptyPasswords .*/PermitEmptyPasswords no/" /etc/ssh/sshd_config

# 6. 配置防火墙
echo "[6/8] 配置防火墙..."
ufw default deny incoming
ufw default allow outgoing
ufw allow $NEW_SSH_PORT/tcp
ufw allow 80/tcp
ufw allow 443/tcp
echo "y" | ufw enable

# 7. 开启 BBR
echo "[7/8] 开启 BBR..."
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
sysctl -p

# 8. 设置时区
echo "[8/8] 设置时区..."
timedatectl set-timezone $TIMEZONE

# 重启 SSH
systemctl restart sshd

echo ""
echo "=========================================="
echo " ✅ 初始化完成!"
echo "=========================================="
echo ""
echo " 新 SSH 端口: $NEW_SSH_PORT"
echo " 新用户: $NEW_USER"
echo " 时区: $TIMEZONE"
echo ""
echo " 请使用以下命令登录:"
echo " ssh -p $NEW_SSH_PORT $NEW_USER@$(curl -s ifconfig.me 2>/dev/null || echo '你的IP')"
echo ""
echo " ⚠️ 重要:请先测试新配置能否登录,再关闭当前终端!"
echo ""

7. How Much More Secure Are We Now?

Step What We Did Why It Matters
System Update Installed the latest patches Fixes known vulnerabilities
Created a New User Stopped logging in directly as root Reduces the risk of accidental mishaps
SSH Keys Swapped passwords for keys Brute-force attacks become impossible
Changed the Port Ditched the default port 22 Lowers the chances of getting scanned
Disabled Passwords Key-only login allowed Completely eliminates password attacks
Disabled Root Root can’t log in directly Makes an attacker’s job much harder
UFW Firewall Only opened necessary ports Shrinks the attack surface
BBR Acceleration Optimized network performance Speeds up access
fail2ban Auto-bans malicious IPs Stops persistent attacks

Once you’ve done all this, your server is already more secure than 90% of the VPS instances out there. Give yourself a pat on the back!


What’s Coming Up Next

In the next post, we’ll dive into a Quick Reference for SSH Key Login Setup, covering the nitty-gritty details like:

  • How to generate keys on different operating systems
  • Managing multiple keys
  • SSH Agent configuration
  • Common SSH client settings

This post was last updated: January 2026

Indie Dev Toolbox Series—hit that follow button!