上一篇 下一篇 分享链接 返回 返回顶部

Linux服务器从SSH登录到开发环境配置,完整部署步骤与验证方法

发布人:Minchunlin 发布时间:2026-10-04 00:03 阅读量:15

这套 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 检查:

4.2 使用 systemd 管理应用配图

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,说明链路已经是:

5.2 验证代理链路配图

Nginx:80 -> 127.0.0.1:8000 -> Gunicorn -> Flask

再检查端口监听情况:

sudo ss -lntp | grep -E ':(22|80|8000)\b'

预期关系如下:

端口预期监听地址对外状态
220.0.0.0:22 或指定地址提供 SSH,需受云防火墙和 UFW 控制
800.0.0.0:80提供 Nginx HTTP 入口
8000127.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"}

如果外部访问失败,按以下顺序检查,避免无序修改:

  1. 确认 SERVER_IP 正确,云防火墙允许 TCP 80。
  2. 在服务器执行 sudo systemctl is-active nginx。
  3. 在服务器执行 sudo nginx -t。
  4. 执行 sudo ufw status verbose,确认 80/tcp 已放行。
  5. 查看 sudo tail -n 50 /var/log/nginx/demo-app.error.log。
  6. 查看应用日志:sudo journalctl -u demo-app.service -n 50 --no-pager。
  7. 确认 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 回滚顺序

出现问题时,按影响范围由小到大处理:

  1. 应用回滚:停止或禁用 demo-app.service,保留项目目录和旧虚拟环境,恢复上一版代码后重新启动。
  2. Nginx 回滚:将 sites-enabled/demo-app 移到 .disabled,通过 nginx -t 后 reload。
  3. SSH 回滚:从控制台或仍存活的管理员会话移除 99-hardening.conf,检查 sshd -t 后 reload。
  4. 防火墙回滚:仅通过控制台执行 ufw disable,恢复 SSH 访问后重新整理允许规则。
  5. 系统更新回滚:系统升级涉及内核和基础库时,优先使用云主机快照或系统备份恢复,不要在没有依赖验证的情况下强行批量降级软件包。

这样完成后,服务器具备清晰的运行边界:SSH 负责管理登录,deploy 用户负责应用文件,Python 虚拟环境隔离依赖,systemd 负责进程存活,Gunicorn 负责应用进程,Nginx 负责外部 HTTP 入口,UFW 和云防火墙共同控制网络暴露面。

目录结构
全文