← 全部章节

12 综合实战 · 01 / 03 · 云端环境

开一台 Ubuntu 云服务器,
把登录入口验证清楚

先让自己的密钥进入普通用户,再逐层收紧认证和网络入口。每次改动后,都用一个新连接确认:你仍能进入正确的环境,并在需要时管理它。

约 15 分钟阅读 · 截至 2026-11-06,Ubuntu 26.04 LTS · 云端命令未实测

你的电脑 私钥留在本地project-server 连接 云网络 · 安全组 22 Ubuntu · UFW 入站规则 22 SSH 服务 验公钥 dev sudo root 先核对服务器的主机指纹普通身份登录,需要时再提权 你的电脑 私钥留在本地连接前核对服务器的主机指纹 连接 SSH 云网络 · 安全组 22 Ubuntu 22 UFW 放行 SSH 服务核验公钥 dev sudo root
  • 本地电脑与密钥
  • 云网络与安全组
  • Ubuntu 主机与用户
图 1 网络决定连接能否到达,SSH 决定以谁的身份进入,sudo 决定何时能管理系统。

学完你能

选资源

镜像定系统,规格定资源

云服务器是一台租来的虚拟机。你选择 Ubuntu 镜像作为系统起点,再给它分配处理器、内存、磁盘与网络;这些资源将承载下一页的 Compose 应用。

创建前填写本练习的选择怎么验证
镜像与架构官方 Ubuntu Server 26.04 LTS;按应用选择 amd64 或 arm64镜像发布者与详情;登录后看 os-release 和 uname
处理器、内存、磁盘可从 2 vCPU、2 GiB 内存、25 GiB 磁盘起步;这是练习预算建议,不是系统最低要求按应用需求调整;磁盘还要容纳镜像、数据与日志
公网与安全组有可达的公网地址;入站 TCP 22 暂只允许你当前的公网 IP确认规则绑定到这台实例;不要使用“全部端口放行”
恢复与费用能打开云控制台的串口或 VNC;先看计费与释放规则确认恢复入口可用,记录磁盘、公网 IP 是否单独计费

vCPU 是分配给虚拟机的虚拟处理器。安全组是云网络一侧的流量规则,尚未进入 Ubuntu 就能筛掉连接。先选好资源与网络,下一节生成密钥、上传公钥后再完成创建。

已有 arm64 应用镜像,你选了 amd64 云主机。增加内存就能解决架构不匹配吗?

架构决定程序面向哪种处理器指令。内存容量不会改变架构;本练习直接匹配主机与应用,避免额外引入模拟执行。

回扣:第 8 章 云服务器的实例、镜像与安全组;第 1 章 准备一台 Ubuntu。

密钥与首登

公钥给服务器,私钥留在本地

在本地电脑生成一对 SSH 密钥。公钥可上传到云控制台,私钥用于证明你拥有这对密钥;给私钥设置口令,保管好备份。本页命令按本地 Linux、macOS 或 WSL 的 Bash 写,先确认新文件名没有被占用。

ssh-keygen -t ed25519 -f ~/.ssh/project-server -C project-server
cat ~/.ssh/project-server.pub

生成时按提示设置口令;若提示文件已存在,停止并换文件名,别覆盖旧密钥。把 .pub 文件那一整行上传为实例的登录公钥,然后完成创建。记录公网地址、初始用户名和实例 ID;初始用户名以该镜像的控制台说明为准,下例用 ubuntu。如果初始账号为 root,管理命令可省去 sudo。

本地私钥不上传 证明 用户公钥服务器核验 核对主机指纹 指纹从可信云控制台获取后再比对

先验证对方,再证明自己

首次登录先比对主机指纹,确认连到预期的服务器。SSH 随后用服务器保存的用户公钥,验证你拥有本地私钥。

私钥口令只解锁本地私钥,不会变成服务器的登录密码。

图 2 登录要双向确认:服务器认出你的密钥,你也要认出服务器。

在云控制台的串口或 VNC 中执行下面的指纹命令,得到可信的主机指纹。再从本地发起 SSH,按提示的算法比对相应指纹;一致才接受。不要通过同一条尚未验证的 SSH 连接获取“可信指纹”。

sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
ssh -o IdentitiesOnly=yes -i ~/.ssh/project-server ubuntu@203.0.113.10

203.0.113.10 是文档示例地址,不能直连;把全页的这个地址换成你的公网 IPv4。若提示其他主机密钥算法,先在控制台核对对应的 /etc/ssh/ssh_host_*_key.pub。登录后,这个窗口记为 A:初始管理员会话,先保留。

验证:成功进入远程 Shell;指纹与控制台一致。超时先查公网路由、安全组和 SSH 端口;认证失败再查用户名、公钥和私钥是否配对。

创建实例时,下面的材料应放在哪里?

  • project-server 私钥
  • project-server.pub 公钥
  • 私钥口令与私钥备份
  • 安全组入站规则
本地保管
云端配置

云端只需要公钥就能验证你的身份。私钥与口令由你保管;安全组属于云网络,独立于密钥认证。

回扣:第 8 章 SSH:登录、密钥与端口转发;第 9 章 密钥与凭据怎么保管。

确认系统

先确认系统,再更新软件包

登录后,先确认你进入的是预期的 Ubuntu 与架构,再更新软件包。apt update 刷新可安装软件的索引,apt upgrade 才安装更新;它们不等于把系统升级到另一发行版。

whoami
cat /etc/os-release
uname -m
df -h /
free -h
sudo apt update
sudo apt upgrade

验证:发行版为 Ubuntu 26.04,架构与所选资源相符(amd64 常显示为 x86_64,arm64 常显示为 aarch64),根磁盘和内存有余量;更新命令成功结束。若系统提示需要重启,在控制台可用的前提下执行 sudo reboot,等待启动后重新建立 A。首次初始化尚未结束或 apt 被占用时,等它结束,不删除锁文件。

只刷新软件索引、还不安装更新,应运行哪条命令?

apt update 更新索引。看到“可升级”只代表有新包可用,仍要执行升级并检查是否需要重启。

回扣:第 5 章 软件装到了哪里;第 11 章 网络与资源排查。

建立日常身份

用普通用户登录,需要时再提权

创建日常用户 dev,把它加入 sudo 组,再只放入你自己的登录公钥。这样你与协作 agent 可以明确知道命令以谁的身份运行、工作目录和文件属于谁。本节适用于全新实例;若 dev 已存在,先检查其用途,不覆盖原有 authorized_keys。

sudo adduser dev
sudo adduser dev sudo
sudo install -d -m 700 -o dev -g dev /home/dev/.ssh
sudo install -m 600 -o dev -g dev /dev/null /home/dev/.ssh/authorized_keys
sudoedit /home/dev/.ssh/authorized_keys

按提示给 dev 设置独立密码,并在编辑器中粘贴本地 project-server.pub 的完整一行后保存。authorized_keys 是该用户允许用于登录的公钥列表;不复制云平台其他用途的密钥。若初始账号是 root,A 中的管理命令可以省去 sudo。

ssh -o IdentitiesOnly=yes -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no -i ~/.ssh/project-server dev@203.0.113.10
whoami
id
sudo -k
sudo -v
sudo whoami
ls -ld ~/.ssh ~/.ssh/authorized_keys

验证:whoami 是 dev,id 包含 sudo 组;sudo -v 能用 dev 的密码验证,sudo whoami 是 root。SSH 目录与公钥文件归 dev 所有,权限分别为 700 和 600。B 禁用了密码回退,因此成功进入才证明密钥路径可用。

B 已登录为 dev,但 sudo 验证失败。下一步该做什么?

能进 Shell 只证明登录成功,还没有证明管理能力可用。

应先确认替代的管理入口,再收紧初始入口。

SSH 认证和 sudo 授权是两层验证。先在 A 修好组成员或密码;新登录会话会获得更新后的组信息,验证两层都通过后再继续。

回扣:第 1 章 进程、用户与权限;第 2 章 家目录。

收紧认证

新连接验证通过后,再关闭旧入口

在 B 中添加独立的 SSH 配置片段。关闭密码认证与键盘交互认证,保留公钥认证,并禁止 root 直接通过 SSH 登录;普通用户仍可通过 sudo 管理系统。

会话 A持续保留 验证路线 B 1 · dev 用密钥登录 2 · 验证 sudo 3 · 写入认证配置 4 · 校验有效配置 5 · 重载 SSH 服务 6 · 新连接重新验证
  1. 在本地新终端建立 B,明确禁用密码回退。猜一猜:已有 A 还在线,能证明新登录也能成功吗?
  2. 在 B 验证 sudo。登录身份与管理授权分别检查,A 继续保留。
  3. 在 B 写入配置片段,不修改现有会话来“模拟”新登录。
  4. 语法检查通过,还要检查最终生效值。猜一猜:文件里写了 no,为什么最终值仍可能是 yes?
  5. 配置合格后才重载;已有会话不会自动重新认证。
  6. 第三个本地终端重新连接并验证 sudo;这次成功才证明新配置下仍可管理主机。
图 3 A 保留恢复能力,B 跑通替代入口,重载后再用全新连接验证最终状态。
sudoedit /etc/ssh/sshd_config.d/00-project.conf

在这个新片段中保存以下内容。若文件已存在,先检查原内容,不直接覆盖。

PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
sudo /usr/sbin/sshd -t
read -r CLIENT_IP CLIENT_PORT SERVER_IP SERVER_PORT <<< "$SSH_CONNECTION"
sudo /usr/sbin/sshd -T -C "user=dev,addr=$CLIENT_IP,host=$CLIENT_IP,laddr=$SERVER_IP,lport=$SERVER_PORT" | grep -E '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin) '
sudo /usr/sbin/sshd -T -C "user=root,addr=$CLIENT_IP,host=$CLIENT_IP,laddr=$SERVER_IP,lport=$SERVER_PORT" | grep '^permitrootlogin '
sudo systemctl reload ssh.service

验证:sshd -t 成功且没有诊断信息;最终值中公钥认证为 yes,另外三项为 no,root 连接条件下也为 permitrootlogin no。不符合就停在重载之前,检查已有片段和 Match 条件。重载后在第三个本地终端重新运行 B 的密钥连接命令,复测 sudo -k、sudo -v 与 sudo whoami,不要只看旧 A、B 还在线。

深入一点:为什么用 00 开头,还要检查最终值?

Ubuntu 在主配置顶部包含 sshd_config.d/*.conf,大多数选项取先遇到的值。00-project.conf 通常排在 cloud-init 片段之前,但已有更早配置、主文件位置或 Match 条件仍会影响结果。-T -C 按给定用户和连接条件输出最终配置;若使用基于主机名的 Match,需用实际解析的客户端主机名替代 host 值。因此上面的命令分别检查 dev 与 root 的连接条件。以后修改 cloud-init 或认证策略仍要复核。

重载后旧 A 仍能运行命令,是否说明新密钥登录已经验证成功?

已有会话已完成认证。只有新建连接才会使用重载后的策略;如果失败,保留的 A 或 B 可用于检查片段、恢复原设置并重新校验。

回扣:第 8 章 SSH;第 3 章 改配置为什么不生效;第 11 章 服务与日志。

收紧网络

先放行 SSH,再启用入站限制

安全组在云侧控制流量,UFW在 Ubuntu 中管理主机防火墙规则。两层都先只给管理者开放 SSH 的 TCP 22,再为下一页预留 Web 的 TCP 80、443;放行端口不会自动启动 Web 服务。

sudo apt install ufw
read -r CLIENT_IP CLIENT_PORT SERVER_IP SERVER_PORT <<< "$SSH_CONNECTION"
sudo ufw status numbered
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from "$CLIENT_IP" to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
sudo ufw status numbered

这里的 CLIENT_IP 取自服务器看到的当前 SSH 来源地址。如果经过 VPN、跳板机或 NAT,它可能不同于你电脑的局域网地址,云安全组也要按实际入站来源配置。启用前确认 SSH 允许规则已添加,并通过 status numbered 核对是否有旧的宽泛允许规则;新实例也可能有预置规则,必要时按编号从大到小删除多余项。

验证:UFW 为 active,默认拒绝入站,允许项仅有指定来源的 TCP 22 和 Web 的 TCP 80、443;安全组也没有其他公网入站端口。启用后再新建一个密钥连接确认 SSH 可达。换网络后先更新两层 SSH 来源规则,再结束当前会话。

安全组:先限制公网可达端口 主机服务 Ubuntu UFW 主机入站 允许后到达 SSH 等服务 Docker 发布经转发路径 容器端口 云安全组仍限制两条路径的公网入口

同一台主机,两条流量路径

访问主机上的 SSH,流量受 UFW 主机入站规则管理。Docker 发布端口则可能把流量提前转发给容器。

两条路径都应受到云安全组的公网入口限制。下一页部署后,要从外部确认实际可达范围。

图 4 Docker 发布端口可能绕过 UFW 的主机入站规则,云安全组仍应限制公网可达范围。

下一页用 Compose 发布端口时,要再次检查宿主机绑定地址与安全组。只给本机反向代理使用的端口绑定到 127.0.0.1;不要因为 UFW 没写 8080,就认定 Docker 的 8080:80 无法被外部访问。依据 Docker 官方防火墙说明。

UFW 只放行了 22、80、443。后来发布了 Docker 的 8080 端口,能据此断言公网访问不了 8080 吗?

容器发布端口的转发路径可能早于 UFW 的主机入站处理。

端口是否可达取决于网络规则、绑定地址与服务监听,和浏览器是否启动无关。

不能只用 UFW 状态证明容器端口的隔离。把应用端口绑定到合适地址,限制云安全组,并从外部验证最终暴露范围。

深入一点:如果新连接失败,按什么顺序查?

先保留可用会话,在云控制台核对公网地址、实际 SSH 端口和安全组来源;再查 sudo ufw status numbered、sudo ss -lntp 和 sudo journalctl -u ssh.service -n 50 --no-pager。超时先看路径,认证被拒绝再看账号、公钥权限与 SSH 策略。若所有 SSH 会话都断开,从已验证可用的云控制台修复具体规则;不要用开放所有入站来代替定位。

回扣:第 4 章 IP、端口与 localhost;第 8 章 安全组;第 6 章 容器端口。

准备运行环境

主机装引擎,应用环境放进容器

Docker 将应用及其运行环境组织成镜像,再由服务器上的引擎启动容器。这样下一页可以通过 Compose 文件描述多个服务,减少手工安装依赖的差异;本页先把引擎与 Compose 插件准备好。

截至 2026-11-06,Docker 官方 Ubuntu 安装文档列出对 26.04 LTS 的支持。下面针对干净的新实例,按 Docker 官方 apt 仓库安装流程配置;如果已装 docker.io、podman-docker、containerd 或 runc 等冲突包,先按该文档核查,不在有业务的主机上直接卸载。

Ubuntu 主机 dev → sudo docker请求创建 Docker 引擎 启动 容器

引擎是这台服务器的系统服务

CLI 是命令入口,Compose 是多个服务的配置入口;两者都通过 Docker 引擎创建和管理容器。

因此要分别检查客户端、引擎与 Compose 插件,再用一个小容器验证整条路径。

图 5 CLI 与 Compose 都请求主机上的 Docker 引擎管理容器,安装位置和运行身份因此要分清。
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

下载的是用于验证软件包来源的公开签名密钥。下一段把仓库地址、发行代号与架构写入 apt 的源配置;整段粘贴,末尾 EOF 要独占一行。

sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

上面是多行 Shell 输入,不是命令输出。软件源文件记录“从哪里安装什么架构的软件”;Compose 插件随这些软件包一起安装,使用 docker compose(中间是空格)。

sudo systemctl is-active docker.service
sudo docker version
sudo docker compose version
sudo docker run --rm hello-world

验证:Docker 服务为 active,docker version 能同时查询 Client 和 Server,Compose 插件可用;hello-world 成功运行后自动删除容器。拉取失败先查网络、代理与证书,不把它直接判断成权限问题;版本号以你实际机器为准。

用自己的话解释:为什么本页保留 dev 的 sudo 密码,却关闭 SSH 密码登录,并继续写 sudo docker?

SSH 的远程认证、sudo 的本地提权和 Docker 引擎的控制权属于不同边界。用密钥进入 dev,再明确授权管理操作,既可验证,也方便交接。

  • SSH 禁用密码认证不会删除用户的本地密码。
  • sudo 在服务器上按规则验证并提权。
  • Docker 引擎控制权接近管理员权限,因此显式使用 sudo。

回扣:第 5 章 apt 与安装位置;第 6 章 Docker 的结构、第一次跑容器、Docker Compose。

交接下一页

交接验证结果,再开始部署应用

现在应有一台能用密钥进入 dev、能按需提权、网络边界已核对且 Docker 可运行的 Ubuntu。把下面的证据记录到自己的实验笔记,交给协作 agent 的是环境信息与验证结论,密钥和口令留在凭据管理处。

准备进入应用部署前,哪份交接记录最有用?

命令记录说明做过什么,验证结果才说明当前环境实际可用。

交接环境不需要公开凭据。私钥与密码应由凭据管理系统保管。

后续部署依赖可重现的环境和明确的权限、网络边界。记录验证结果,能帮助你和 agent 判断故障发生在哪一层。

回扣:第 7 章 与 agent 协作;第 8 章 本地、远程、云端怎么选。

核对依据

来源

截至 2026-11-06 核对以下官方文档。本页云端流程未实测,终端只列输入,不展示版本号或模拟输出;请按各步验证条件记录自己的结果。

  1. Ubuntu releases——官方云镜像、发行版与架构选择。
  2. Ubuntu Server:OpenSSH server——配置片段、语法校验与公钥登录。
  3. Ubuntu 26.04:ssh-keygen(1);sshd(8);sshd_config(5)——指纹、有效配置、认证开关与 Match。
  4. Ubuntu Server:User management;Install and manage packages——用户、sudo 与软件包更新。
  5. Ubuntu Server:Firewall;Ubuntu 26.04:ufw(8)——来源限制、启用顺序与 IPv6。
  6. Docker:Install Docker Engine on Ubuntu——支持平台、apt 源、Engine 和 Compose 插件。
  7. Docker:Packet filtering and firewalls;Linux post-installation steps——UFW 边界与 docker 组权限。