Linux服务器从SSH登录到开发环境配置,完整部署步骤与验证方法
这套 Linux 服务器入门流程以 Ubuntu Server 22.04/24.04 LTS、x86_64 架构、systemd 服务管理和 Python Web 应用为例,目标是完成从 SSH 登录、账号安全、系统依赖安装,到虚拟环境、应用服务、Nginx 入口和防火墙验证的完整配置。最终状态应当是:管理员使用密钥登录,应用由独立用户运行,Gunicorn 仅监听本机端口,Nginx 对外提供 HTTP 访问,所有关键服务都能通过命令检查和日志确认。

开始前需要准备服务器公网 IP、初始登录账号及密码或密钥、客户端 SSH 工具,以及允许访问 TCP 22 端口的云防火墙规则。以下命令适用于 Ubuntu Server 22.04/24.04 LTS;如果系统是其他发行版,不要直接照搬 apt、UFW 和服务路径,应先确认对应的软件包管理器和 OpenSSH 配置方式。
1. 确认系统和登录条件
1.1 连接服务器
Linux、macOS 和 Windows PowerShell 通常都可以直接使用 OpenSSH。将 SERVER_IP 替换为实际服务器地址:
ssh -p 22 root@SERVER_IP
如果初始账号不是 root,应改为云平台提供的管理员账号,例如:
ssh -p 22 ubuntu@SERVER_IP
登录后先确认操作系统、内核、架构、磁盘和内存状态:
cat /etc/os-release
uname -m
uname -r
df -h /
free -h
id
systemctl is-system-running || true
典型结果可能类似:
PRETTY_NAME="Ubuntu 24.04.1 LTS"
x86_64
6.8.0-xx-generic
running
这里重点检查以下内容:
PRETTY_NAME应为 Ubuntu 22.04 或 24.04 LTS。uname -m为x86_64或目标应用支持的架构。- 根分区至少预留数 GB 空间,Python 依赖、日志和系统升级都需要额外磁盘。
systemctl is-system-running显示running较理想;如果是degraded,先检查异常服务,不要立即部署业务。- 当前账号需要具备
sudo权限,或者当前就是root。
如果系统版本不符合预期,先停止后续操作,避免因为软件包版本、服务名称或配置目录不同造成故障。
1.2 创建日常运维账号
不建议长期使用 root 运行应用。使用初始管理员账号创建 deploy 用户,并授予必要的 sudo 权限:
adduser deploy
usermod -aG sudo deploy
执行 adduser 时按提示设置密码。随后在本地客户端确认是否已有 SSH 密钥:
test -f ~/.ssh/id_ed25519.pub && echo "SSH_PUBLIC_KEY_FOUND" || echo "SSH_PUBLIC_KEY_NOT_FOUND"
如果没有密钥,可在本地生成一对密钥。私钥只保存在本地,不要上传到服务器:
ssh-keygen -t ed25519 -C "deploy@server"
将公钥复制到服务器:
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@SERVER_IP
如果客户端没有 ssh-copy-id,可以先查看本地公钥内容:
cat ~/.ssh/id_ed25519.pub
再登录服务器执行以下操作,并将公钥完整粘贴到 authorized_keys 中:
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
在原 SSH 会话保持不关闭的情况下,新开一个终端验证密钥登录:
ssh -i ~/.ssh/id_ed25519 deploy@SERVER_IP 'id -un && hostname'
预期输出中应包含:
deploy
your-server-hostname
只有在这一步验证成功后,才进行 SSH 安全加固。
2. 更新系统并安装基础依赖
2.1 更新软件包
系统更新可能替换内核、OpenSSH 或其他基础组件。生产服务器执行前应确认已有云主机快照、系统备份或可用的控制台入口,并安排维护窗口。
sudo apt-get update
sudo apt-get upgrade -y
如果内核或关键系统库发生升级,可以检查是否需要重启:
test -f /var/run/reboot-required && echo "REBOOT_REQUIRED" || echo "NO_REBOOT_REQUIRED"
需要重启时,不要在 SSH 会话中直接关闭窗口。先确认新账号密钥可用,再执行:
sudo reboot
重启属于中断性操作,预计会暂时断开 SSH 和业务连接。重启后重新检查:
ssh -i ~/.ssh/id_ed25519 deploy@SERVER_IP
2.2 安装开发和运行依赖
本示例的目标应用使用 Python,基础依赖包括 Git、编译工具、Python 虚拟环境、Nginx 和 UFW:
sudo apt-get install -y \
git \
curl \
ca-certificates \
build-essential \
pkg-config \
python3 \
python3-venv \
python3-pip \
python3-dev \
nginx \
ufw
检查安装结果和运行时版本:
git --version
python3 --version
python3 -m pip --version
nginx -v
systemctl is-active nginx
Ubuntu 22.04 和 24.04 的 Python 小版本可能不同,例如分别常见为 Python 3.10 和 Python 3.12。应用如果锁定了特定 Python 版本,应以项目依赖文件和测试结果为准,不要仅因为系统能安装就强行替换系统 Python。
Git 全局配置应使用实际维护人员信息,下面是示例值:
sudo -u deploy -H git config --global user.name "Server Developer"
sudo -u deploy -H git config --global user.email "developer@example.com"
sudo -u deploy -H git config --global init.defaultBranch main
3. 加固 SSH 登录
3.1 先备份并检查配置
SSH 配置修改错误可能导致新的连接失败。下面先备份主配置文件,再写入独立的配置片段:
sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.pre-hardening
sudo install -d -m 755 /etc/ssh/sshd_config.d
写入加固配置:
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf > /dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
EOF
这些设置的作用如下:
| 配置项 | 作用 |
|---|---|
PermitRootLogin no | 禁止通过 SSH 直接登录 root |
PasswordAuthentication no | 关闭密码认证,减少密码撞库风险 |
KbdInteractiveAuthentication no | 关闭交互式键盘认证 |
PubkeyAuthentication yes | 保留 SSH 公钥认证 |
先测试语法,再重新加载服务:
sudo /usr/sbin/sshd -t
sudo systemctl reload ssh
如果 sshd -t 没有输出,通常表示语法检查通过。随后再次打开一个终端验证:
ssh -i ~/.ssh/id_ed25519 deploy@SERVER_IP 'id -un'
确认输出为 deploy 后,当前连接和新连接都正常,才可以关闭旧的 root 会话。不要在尚未验证密钥的情况下执行这一步,否则可能把自己锁在服务器外。
3.2 SSH 配置失败时的处理
如果配置检查失败,先不要执行 reload。查看具体报错:
sudo /usr/sbin/sshd -t
如果 reload 后新终端无法登录,但已有 SSH 会话仍然存在,可在旧会话中恢复:
sudo mv /etc/ssh/sshd_config.d/99-hardening.conf \
/etc/ssh/sshd_config.d/99-hardening.conf.disabled
sudo /usr/sbin/sshd -t
sudo systemctl reload ssh
如果现有会话也已断开,应通过云平台控制台执行恢复。只有在确认配置文件已恢复且 sshd -t 通过后,才重新加载 SSH 服务。
4. 创建 Python 开发环境
4.1 准备项目目录和虚拟环境
使用 /srv/demo-app 作为示例项目目录,应用由 deploy 用户拥有:
sudo install -d -o deploy -g deploy -m 0755 /srv/demo-app
创建依赖文件:
sudo tee /srv/demo-app/requirements.txt > /dev/null <<'EOF'
Flask==3.0.3
gunicorn==22.0.0
EOF
创建用于验证部署链路的健康检查程序:
sudo tee /srv/demo-app/app.py > /dev/null <<'EOF'
from flask import Flask
app = Flask(__name__)
@app.get("/health")
def health():
return {
"status": "ok",
"service": "demo-app"
}
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000)
EOF
调整文件所有者:
sudo chown -R deploy:deploy /srv/demo-app
以 deploy 用户创建虚拟环境并安装依赖:
sudo -u deploy -H bash -c '
cd /srv/demo-app &&
python3 -m venv .venv &&
.venv/bin/python -m pip install --upgrade pip &&
.venv/bin/python -m pip install -r requirements.txt
'
验证 Python、Flask 和 Gunicorn 是否可用:
sudo -u deploy /srv/demo-app/.venv/bin/python -c \
'import flask, gunicorn; print(flask.__version__); print("PYTHON_ENV_OK")'
预期结果包含 Flask 版本号和:
PYTHON_ENV_OK
虚拟环境只作用于 /srv/demo-app/.venv,不会覆盖 Ubuntu 的系统 Python。应用依赖应写入 requirements.txt 或项目自身的锁定文件,避免直接向系统 Python 执行全局 pip install。
4.2 使用 systemd 管理应用
开发阶段可以使用 Flask 自带服务器临时测试,但上线运行不应依赖开发服务器。这里使用 Gunicorn,并让应用只监听本机 127.0.0.1:8000,不直接暴露应用端口。
创建 systemd 单元:
sudo tee /etc/systemd/system/demo-app.service > /dev/null <<'EOF'
[Unit]
Description=Demo Python Web Application
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/srv/demo-app
Environment=PYTHONUNBUFFERED=1
ExecStart=/srv/demo-app/.venv/bin/gunicorn --workers 2 --bind 127.0.0.1:8000 --access-logfile - --error-logfile - app:app
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
--workers 2 是适合小型示例的参考值,不代表所有业务都应固定使用两个进程。实际数量应结合 CPU、内存和应用类型测试。
加载并启动服务:
sudo systemctl daemon-reload
sudo systemctl enable --now demo-app.service
按顺序进行状态、端口、日志和 HTTP 检查:

sudo systemctl status demo-app.service --no-pager
sudo ss -lntp | grep ':8000'
curl -fsS http://127.0.0.1:8000/health
sudo journalctl -u demo-app.service -n 50 --no-pager
成功时,curl 可能返回:
{"service":"demo-app","status":"ok"}
同时,端口检查应显示 127.0.0.1:8000,而不是 0.0.0.0:8000。这说明应用只接受本机请求,外部访问将由 Nginx 统一处理。
5. 配置 Nginx 反向代理
5.1 写入站点配置
创建 Nginx 站点配置:
sudo tee /etc/nginx/sites-available/demo-app > /dev/null <<'EOF'
server {
listen 80;
listen [::]:80;
server_name _;
access_log /var/log/nginx/demo-app.access.log;
error_log /var/log/nginx/demo-app.error.log;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
EOF
启用站点:
sudo ln -sfn /etc/nginx/sites-available/demo-app \
/etc/nginx/sites-enabled/demo-app
Ubuntu 默认可能已经启用了 sites-enabled/default。如果需要让示例配置接管 80 端口,先备份并移走默认软链接。该操作只影响 Nginx 站点匹配,不会删除项目文件:
if [ -e /etc/nginx/sites-enabled/default ]; then
sudo mv /etc/nginx/sites-enabled/default \
/etc/nginx/sites-enabled/default.disabled
fi
检查配置并平滑加载:
sudo nginx -t
sudo systemctl reload nginx
只有在 nginx -t 输出 syntax is ok 和 test is successful 后,才执行 reload。配置错误时,Nginx 不会因为 nginx -t 自动改变当前运行配置。
5.2 验证代理链路
在服务器本机验证 Nginx:
curl -i http://127.0.0.1/health
如果返回 HTTP 200 和 JSON,说明链路已经是:

Nginx:80 -> 127.0.0.1:8000 -> Gunicorn -> Flask
再检查端口监听情况:
sudo ss -lntp | grep -E ':(22|80|8000)\b'
预期关系如下:
| 端口 | 预期监听地址 | 对外状态 |
|---|---|---|
| 22 | 0.0.0.0:22 或指定地址 | 提供 SSH,需受云防火墙和 UFW 控制 |
| 80 | 0.0.0.0:80 | 提供 Nginx HTTP 入口 |
| 8000 | 127.0.0.1:8000 | 仅本机访问,不应直接暴露 |
如果本机访问 80 端口正常,但外部访问失败,应继续检查云防火墙、UFW 和服务器公网 IP,而不是先修改 Python 代码。
6. 配置防火墙并进行外部验证
6.1 调整 UFW 规则
防火墙调整可能立即影响远程管理。必须先放行 SSH,再启用或修改默认入站策略;如果使用非 22 端口,应将下面的端口替换为实际端口。
先查看现有规则:
sudo ufw status verbose
放行 SSH 和 HTTP:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw default deny incoming
sudo ufw default allow outgoing
在确认云防火墙已允许 TCP 22 后启用 UFW:
sudo ufw --force enable
sudo ufw status numbered
示例规则应至少包含:
22/tcp ALLOW IN
80/tcp ALLOW IN
如果服务器还有其他正在使用的入站服务,不要直接套用 default deny incoming,应先列出端口和业务依赖,再补充明确规则。默认拒绝会影响未列入允许列表的服务。
6.2 从外部客户端验证
在本地电脑执行:
curl -i http://SERVER_IP/health
预期结果类似:
HTTP/1.1 200 OK
Content-Type: application/json
{"service":"demo-app","status":"ok"}
如果外部访问失败,按以下顺序检查,避免无序修改:
- 确认
SERVER_IP正确,云防火墙允许 TCP 80。 - 在服务器执行
sudo systemctl is-active nginx。 - 在服务器执行
sudo nginx -t。 - 执行
sudo ufw status verbose,确认 80/tcp 已放行。 - 查看
sudo tail -n 50 /var/log/nginx/demo-app.error.log。 - 查看应用日志:
sudo journalctl -u demo-app.service -n 50 --no-pager。 - 确认
curl http://127.0.0.1:8000/health仍然成功。
不同结果对应不同故障范围:
| 检查结果 | 通常说明 |
|---|---|
| 8000 本机失败 | Python 应用、虚拟环境或 systemd 服务异常 |
| 8000 成功、80 失败 | Nginx 配置、Nginx 服务或端口监听异常 |
| 本机 80 成功、外部 80 失败 | 云防火墙、UFW、公网地址或网络入口问题 |
| SSH 失败但 HTTP 正常 | SSH 端口、密钥、账号权限或防火墙规则问题 |
7. 常见失败处理
7.1 SSH 公钥认证失败
在客户端使用详细模式查看认证过程:
ssh -vv -i ~/.ssh/id_ed25519 deploy@SERVER_IP
在服务器上检查目录和文件权限:
sudo stat -c '%A %U:%G %n' \
/home/deploy \
/home/deploy/.ssh \
/home/deploy/.ssh/authorized_keys
常见正确权限是:
/home/deploy/.ssh drwx------ deploy:deploy
/home/deploy/.ssh/authorized_keys -rw------- deploy:deploy
如果权限不正确,可以修复:
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
同时确认服务器仍在监听 SSH:
sudo ss -lntp | grep ':22'
sudo journalctl -u ssh -n 50 --no-pager
不要在没有控制台入口和备用管理员会话时反复修改 SSH 配置。
7.2 Python 依赖安装失败
先确认磁盘、网络和 Python 版本:
df -h /
python3 --version
sudo -u deploy /srv/demo-app/.venv/bin/python -m pip --version
查看具体安装日志:
sudo -u deploy /srv/demo-app/.venv/bin/python -m pip install -r /srv/demo-app/requirements.txt
如果某个依赖需要编译,确认 build-essential、python3-dev 和相关系统开发库已经安装。不要直接删除当前可用虚拟环境;可以先改名保存,再重新创建:
sudo mv /srv/demo-app/.venv \
/srv/demo-app/.venv.failed.$(date +%Y%m%d%H%M%S)
然后重新执行虚拟环境创建和依赖安装步骤。确认新环境可用后,再按维护周期清理旧目录。
7.3 systemd 服务启动失败
先查看状态和完整日志:
sudo systemctl status demo-app.service --no-pager
sudo journalctl -u demo-app.service -b -n 100 --no-pager
常见原因包括:
ExecStart路径错误;WorkingDirectory不存在;deploy用户无权读取项目目录;requirements.txt未安装 Gunicorn;- 8000 端口已被其他进程占用;
- Python 应用导入路径不是
app:app。
检查文件和端口:
sudo -u deploy test -x /srv/demo-app/.venv/bin/gunicorn && echo "GUNICORN_FOUND"
sudo -u deploy test -f /srv/demo-app/app.py && echo "APP_FILE_FOUND"
sudo ss -lntp | grep ':8000' || true
修改 unit 文件后必须重新加载:
sudo systemctl daemon-reload
sudo systemctl restart demo-app.service
7.4 Nginx 配置或代理失败
先检查配置,不要直接重启:
sudo nginx -t
再查看错误日志:
sudo tail -n 50 /var/log/nginx/demo-app.error.log
如果 Nginx 返回 502 Bad Gateway,通常表示 Nginx 能够接收请求,但无法连接 127.0.0.1:8000。此时优先检查:
sudo systemctl is-active demo-app.service
curl -i http://127.0.0.1:8000/health
sudo ss -lntp | grep ':8000'
如果需要暂时撤回新站点配置,可保留文件并移除启用链接:
sudo mv /etc/nginx/sites-enabled/demo-app \
/etc/nginx/sites-enabled/demo-app.disabled
sudo nginx -t
sudo systemctl reload nginx
如果之前移动过默认站点且需要恢复:
if [ -e /etc/nginx/sites-enabled/default.disabled ]; then
sudo mv /etc/nginx/sites-enabled/default.disabled \
/etc/nginx/sites-enabled/default
fi
sudo nginx -t
sudo systemctl reload nginx
7.5 防火墙配置后无法访问
如果仍有 SSH 会话,先不要退出。检查规则:
sudo ufw status numbered
sudo ss -lntp | grep -E ':(22|80)\b'
如果已经无法通过 SSH 连接,只能通过云平台控制台处理。可以在确认控制台可用的前提下临时关闭 UFW:
sudo ufw disable
关闭防火墙会扩大入站暴露范围,只应作为短时间故障恢复措施。恢复访问后,应重新添加正确的 SSH 和 HTTP 规则,再启用 UFW:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw --force enable
sudo ufw status verbose
8. 验收与回滚清单
8.1 上线验收
完成部署后,按以下顺序逐项检查:
- [ ]
cat /etc/os-release确认系统版本符合预期。 - [ ]
ssh -i ~/.ssh/id_ed25519 deploy@SERVER_IP可以登录。 - [ ] root SSH 登录和密码认证已在确认密钥可用后关闭。
- [ ]
git --version、python3 --version、nginx -v均可执行。 - [ ]
/srv/demo-app/.venv存在,Flask 和 Gunicorn 可导入。 - [ ]
systemctl is-enabled demo-app.service返回 enabled。 - [ ]
systemctl is-active demo-app.service返回 active。 - [ ]
curl http://127.0.0.1:8000/health返回 HTTP 200。 - [ ] Nginx 配置检查通过,
curl http://127.0.0.1/health返回 HTTP 200。 - [ ] 8000 端口只监听
127.0.0.1,没有直接暴露到公网。 - [ ] UFW 放行了实际 SSH 端口和 80/tcp。
- [ ] 从外部客户端访问
http://SERVER_IP/health成功。 - [ ]
journalctl -u demo-app.service和 Nginx 错误日志没有持续增长的异常。
8.2 回滚顺序
出现问题时,按影响范围由小到大处理:
- 应用回滚:停止或禁用
demo-app.service,保留项目目录和旧虚拟环境,恢复上一版代码后重新启动。 - Nginx 回滚:将
sites-enabled/demo-app移到.disabled,通过nginx -t后 reload。 - SSH 回滚:从控制台或仍存活的管理员会话移除
99-hardening.conf,检查sshd -t后 reload。 - 防火墙回滚:仅通过控制台执行
ufw disable,恢复 SSH 访问后重新整理允许规则。 - 系统更新回滚:系统升级涉及内核和基础库时,优先使用云主机快照或系统备份恢复,不要在没有依赖验证的情况下强行批量降级软件包。
这样完成后,服务器具备清晰的运行边界:SSH 负责管理登录,deploy 用户负责应用文件,Python 虚拟环境隔离依赖,systemd 负责进程存活,Gunicorn 负责应用进程,Nginx 负责外部 HTTP 入口,UFW 和云防火墙共同控制网络暴露面。