Cockpit 与 Webmin 如何选择:Ubuntu VPS 管理面板对比
对比 Cockpit 与 Webmin 在 Ubuntu VPS 上能修改的内容、登录方式及安全边界,说明为何不应将密码登录暴露在公共端口,以及何时应改用 SSH 加 Ansible。
Cockpit 与 Webmin:简短结论
Cockpit 和 Webmin 都是用于通过浏览器管理 Linux 服务器的 Web 面板,但它们解决的问题不同。Cockpit 由发行版自己的软件仓库提供,并通过 systemd、journald、polkit 和 udisks 读取计算机状态,因此它展示的是一台仍然通过 SSH 管理的服务器。Webmin 更早出现,功能范围也更广:它可以为 Apache、BIND、Postfix、MariaDB 以及 Cockpit 不会接触的数十种其他服务写入配置文件,并以 root 身份运行自己的 Web 服务器来完成这些操作。
如果您需要查看单台服务器的实时状态、读取日志和使用应急终端,请安装 Cockpit。如果您需要通过表单编辑器配置不想手动配置的服务,请安装 Webmin。不要让任何一个面板通过公共端口提供密码登录。如果您已经运行两三台以上服务器,通常更实际的答案是两者都不用;与任何面板相比,SSH 加 Ansible 的方式更易于扩展。
每个面板实际可以修改的内容
Cockpit 的基础安装很小,大多数功能区域都是独立软件包,可以不安装:
- systemd 服务和定时器:启动、停止、启用服务,并读取单元文件
- 按单元和优先级筛选的 journal,
journalctl可通过日期选择器筛选 - 本地账户、组成员关系和已授权的 SSH 密钥
- 使用
cockpit-storaged管理存储:分区、LVM 卷组、文件系统和挂载点 - 使用
cockpit-podman管理容器,但它只管理 Podman - 使用
cockpit-packagekit管理软件包更新 - 使用
cockpit-pcp查看 CPU、内存、磁盘和网络图表 - 浏览器标签页中的 root 终端
在 Ubuntu VPS 上,有两个区域看起来像是无法使用,但实际并非如此。Cockpit 的 Networking 页面是 NetworkManager 的前端,而 Ubuntu 服务器镜像使用 netplan 和 systemd-networkd,因此该页面会缺失或为空。不要为了恢复该页面而在远程主机上安装 NetworkManager,因为它会接管网络接口。配置错误还会导致 SSH 会话中断。Cockpit 的防火墙控件是 firewalld 的前端,而 Ubuntu 使用 ufw,因此你完全看不到防火墙控件。你仍需在终端中运行 sudo ufw status。
Webmin 覆盖的功能范围更广,因为它由各服务对应的模块组成,而不是一个单体程序:
- 通过表单配置 Apache、nginx、BIND、Postfix、Dovecot、MariaDB、PostgreSQL 和 Samba
- 用户、组和磁盘配额
- cron 任务和系统时钟
- 软件包更新,以及支持上传和下载的文件管理器
- 防火墙前端,包括 iptables 和 firewalld 对应的前端
- 配置文件备份,以及可将一项更改推送到其他 Webmin 服务器的集群模块
Webmin 会直接编辑 /etc 下的实际文件。表单背后没有隐藏数据库,因此如果 /etc 处于版本控制中,保存表单后查看 sudo git -C /etc diff,就能准确看到该模块写入的内容。这是了解任意 Webmin 页面实际执行了什么操作的最快方法。Webmin 安装和首次登录指南详细介绍了模块树。Virtualmin 和 Usermin 是基于同一引擎构建的独立产品,分别面向共享主机和最终用户;关于暴露面的上述内容同样适用于它们。
每种方式如何进行身份验证
Cockpit 没有自己的用户数据库。其登录页面会在 /etc/pam.d/cockpit 中调用 PAM(可插拔认证模块)堆栈,因此使用的是 Unix 账户和 Unix 密码。默认情况下,root 会被拒绝,因为 /etc/cockpit/disallowed-users 将其列入了拒绝列表。特权操作通过 polkit 执行。界面在执行更改前会再次要求您输入密码。因此,在完成提权前,页面标题可能显示为“有限访问”。
在经过加固的服务器上,这种设计会带来一个常见后果。如果您按照仅使用密钥登录 SSH 并禁用密码认证的方式配置,账户可能根本没有可用密码。此时 Cockpit 登录会被拒绝,但 ssh 仍可正常使用。请在服务器上检查:
sudo passwd -S deploy以 deploy L 开头的输出表示密码已锁定。因此 PAM 没有可接受的密码,您输入的任何密码都无法生效。P 表示已设置可用密码。Cockpit 自己的登录页面不接受 SSH 密钥。密钥仅用于 Cockpit 从当前登录的计算机继续连接到其他主机时进行认证。
Webmin 将自己的用户存储在 /etc/webmin/miniserv.users 中,与 /etc/passwd 分开;也可以配置为使用 Unix 账户进行认证。无论用户的登录 shell 如何设置,获得所有模块权限的 Webmin 用户都相当于该计算机上的 root。Webmin 自带 TOTP(基于时间的一次性密码)支持,也支持在多次登录失败后阻止主机。这两项功能都可在 Webmin Configuration 中启用。只有将第二因素添加到 PAM 后,Cockpit 才能使用第二因素,例如通过 libpam-google-authenticator。
每个组件如何更新
Cockpit 由您的发行版打包。在 Ubuntu 24.04 中,它来自软件仓库;上游项目建议使用 backports 仓库以获取更新的构建版本:
. /etc/os-release
sudo apt update
sudo apt install -t ${VERSION_CODENAME}-backports cockpit
sudo systemctl status cockpit.socket
apt policy cockpitapt policy 会显示已安装的版本及其来源仓库。如果 backports 中没有更新的构建版本,apt 会回退到软件仓库中的版本,这没有问题。cockpit.socket 应显示为 active (listening)。之后,安全修复会与内核通过同一次 unattended-upgrades 运行获取,发布者也是您已经信任的发布者。
Webmin 不在 Ubuntu 的软件仓库中。官方安装方式会先添加 Webmin 自己的软件仓库和签名密钥:
curl -o webmin-setup-repo.sh https://raw.githubusercontent.com/webmin/webmin/master/webmin-setup-repo.sh
sudo sh webmin-setup-repo.sh
sudo apt-get install webmin --install-recommends运行该脚本前请先阅读,因为它会以 root 身份运行。从此以后,服务器上的每次 apt upgrade 也会从 Webmin 的软件仓库获取更新。这意味着您在该服务器上新增了一个具有 root 级信任的发布者。Webmin 的实际代价就在这里,因此有必要说明一个具体例子:CVE-2019-15107 是多个 1.9x 软件包中的后门,可执行未经身份验证的命令。该漏洞之所以影响用户,是因为项目的构建主机遭到入侵,而不是源代码仓库遭到入侵。发行版打包无法完全避免此类问题,但会增加一个由您无需自行维护的构建和审查环节。
为何两者都不应使用公网端口
Cockpit 监听 TCP 9090,Webmin 监听 TCP 10000。两者都通过 TLS(传输层安全)提供服务,并使用自签名证书,因此首次访问时会先看到浏览器警告。创建并信任自签名证书说明该警告能告诉您什么,以及不能告诉您什么。这两个端口都会持续受到扫描,而且两个面板都可进入 root,因此一旦密码被猜中或重复使用,服务器就会完全失陷。
安全做法是让面板绑定到 localhost,然后通过 SSH 隧道访问。对于 Cockpit,覆盖其 socket 单元:
sudo systemctl edit cockpit.socket[Socket]
ListenStream=
ListenStream=127.0.0.1:9090必须单独保留空的 ListenStream= 行。systemd 会向列表设置追加内容,因此如果没有这一行,单元会保留原有的 0.0.0.0:9090,并添加新地址,面板仍会暴露在公网。应用覆盖配置,然后检查当前监听的地址:
sudo systemctl daemon-reload
sudo systemctl restart cockpit.socket
sudo ss -lntp | grep 9090输出必须显示 127.0.0.1:9090。如果显示 *:9090 或 0.0.0.0:9090,说明覆盖配置未生效。现在从您自己的计算机建立隧道,并访问 https://localhost:9090:
ssh -N -L 9090:127.0.0.1:9090 deploy@203.0.113.10本地端口应与远程端口保持一致。Cockpit 会将浏览器的 Origin 标头与它认为自身提供服务的地址进行比较。因此,使用本地端口 9999 建立的隧道可以加载登录页面,但登录时会失败;journalctl -u cockpit 会记录被拒绝的来源。如果需要使用不同的本地端口,请在 /etc/cockpit/cockpit.conf 中指定:
[WebService]
Origins = https://localhost:9999 https://127.0.0.1:9999使用 sudo systemctl restart cockpit.socket 重启服务,使该设置生效。对于 Webmin,对应设置位于 /etc/webmin/miniserv.conf:
bind=127.0.0.1sudo systemctl restart webmin
sudo ss -lntp | grep 10000
ssh -N -L 10000:127.0.0.1:10000 deploy@203.0.113.10Webmin 还会检查表单提交中的 Referer 标头,并拒绝看起来来自其他主机的请求。这正是首次尝试使用反向代理时会失败的原因。同一文件中的 referers= 行用于允许代理的主机名,webprefix= 用于告知 Webmin 它位于某个路径下。
另一种选择是使用经过身份验证的反向代理:前端运行 nginx,并由 Authentik 单点登录层负责登录。这种方式可行,但次于 SSH 隧道。面板在代理后仍以 root 身份运行,而且您需要维护两个入口,而不是一个。隧道完全不会向互联网新增监听服务,并且可以复用您已经妥善保护的 SSH 密钥。
已运行生产服务的服务器应选择哪个面板
Cockpit,原因有两个,而且在其他人依赖这台机器时尤其重要。它由 socket 激活,因此 cockpit-ws 仅在会话打开期间运行,不会有永久驻留、等待端口连接的 root 守护进程。它也不会接管任何内容:移除软件包后,所有服务仍会完全按原样运行,因为 Cockpit 不存储自己的配置。无论是否有人登录,Webmin 的 miniserv.pl 都会持续驻留。使用 systemctl status webmin 检查它占用的资源,该命令会输出运行中进程的常驻内存。
如果需要 Webmin 的 DNS 或邮件模块,请为它们单独提供一台服务器。只执行一项工作并绑定到 127.0.0.1 的 Webmin 服务器,其风险是可控的。让 Webmin 与面向客户的应用共享主机则不是这样。安装任一面板前,先完成基础配置:新 VPS 上的前十分钟介绍了两个面板都假定已经存在的非 root 用户和防火墙。
不属于上述两种情况
面板按服务器分别配置,需要手动操作,也不会记录更改了什么或为什么更改。管理一台服务器时这没有问题。服务器达到 5 台后,您会不断重复相同操作;达到 20 台后,您甚至需要猜测哪台服务器没有完成更改。Cockpit 可以通过 SSH 将其他主机添加到同一会话,但近期版本默认禁用此功能,并要求在 /etc/cockpit/cockpit.conf 中配置 AllowMultiHost=yes;即使如此,您仍然需要在界面中将相同更改点击 5 次。
另一种方法是直接使用 SSH,并将配置保存在 git 存储库中。在一个位置管理多台 Linux 服务器介绍了这种配置的基本结构;第一个 Ansible playbook则从一个可通过 diff 审查的文件,为每台主机应用相同的防火墙规则。容器管理也应采用相同方式:按照Docker Compose 基础指南中的做法,通过 git 中的文件使用 docker compose up -d 通过 SSH 执行操作,比在任何面板中逐项点击更可靠;而且 Cockpit 本身并不管理 Docker。
对于终端不擅长的工作,例如查看指标图表或找出 40 个单元中哪些启动失败,请使用面板。对于任何需要执行超过 2 次的操作,请使用代码。
故障模式与您将看到的字符串
Cockpit 拒绝 SSH 接受的密码。 该账户仅支持密钥登录。sudo passwd -S alice 会在第二个字段输出 L,因此 PAM 没有可检查的密码。使用 sudo passwd alice 设置密码,或者继续使用该账户进行 SSH 登录,并以其他用户登录 Cockpit。
即使密码正确,Cockpit 仍拒绝 root。 /etc/cockpit/disallowed-users 会列出 root。请使用具有 sudo 权限的普通用户登录。这是预期的登录方式,因为 polkit 随后会记录是哪位用户执行了提权。
Cockpit 不显示 Networking 或 Firewall 页面。 这些页面需要 NetworkManager 和 firewalld。Ubuntu VPS 使用 netplan、systemd-networkd 和 ufw,因此不会显示这些页面。系统没有故障,继续通过 SSH 使用 ufw 即可。
Cockpit 登录页面可通过隧道加载,但登录失败。 本地端口与远程端口不同,因此 Origin 检查失败,journalctl -u cockpit 会显示该问题。请匹配两个端口,或在 /etc/cockpit/cockpit.conf 中设置 Origins。
将 Webmin 放在代理后面后,表单提交失败。 Referer 检查会拒绝这些请求。将代理主机名添加到 /etc/webmin/miniserv.conf 中的 referers=,如果面板通过路径提供服务,还应设置 webprefix=。
您不确定面板是否对外暴露。 sudo ss -lntp | grep -E '9090|10000' 可从服务器本身检查这一点;Webmin 会将每次登录尝试写入 /var/webmin/miniserv.log。更改监听方式后,建议查看一次该日志。
FAQ
对于单台 Ubuntu VPS,Cockpit 和 Webmin 哪个更好?
对大多数用户而言,Cockpit 更合适,因为它来自 Ubuntu 官方软件仓库,会随系统一起获得补丁,并且只在浏览器会话打开期间运行。如果需要使用基于表单的编辑器来配置 Cockpit 不支持的服务(例如 BIND 或 Postfix),可以选择 Webmin,但需要接受以下代价:其 Web 服务器始终以 root 身份运行,更新也来自 Webmin 自己的软件仓库。
可以在同一台服务器上运行 Cockpit 和 Webmin 吗?
可以。它们使用不同的端口,即 9090 和 10000,因此不会冲突,因为它们都是直接编辑系统,而不是独占系统。不过,这样做并不划算。两个面板都会在同一台机器上提供一个具备 root 权限的独立登录入口,因此只是为了少执行几次操作,却将暴露面增加了一倍。如果同时安装两者,请将它们绑定到 127.0.0.1,并通过 SSH 隧道访问。
将端口 9090 或 10000 开放到互联网安全吗?
使用密码登录时不安全。这两个面板都可以访问 root 权限,开放端口后,通常几小时内就会被常规扫描发现。将面板绑定到 127.0.0.1,然后运行 ssh -N -L 9090:127.0.0.1:9090 user@host 并访问 https://localhost:9090。使用 sudo ss -lntp | grep 9090 确认结果,其中必须显示 127.0.0.1:9090,而不是 0.0.0.0:9090。经过身份验证的反向代理是另一个可接受的方案。
为什么 SSH 使用密钥可以登录,但 Cockpit 登录失败?
Cockpit 通过 PAM 使用 Unix 密码进行身份验证,其登录页面不接受 SSH 密钥。在经过加固的服务器上,该账户通常没有可用密码。运行 sudo passwd -S youruser:如果第二个字段中出现 L,表示密码已锁定,因此 PAM 没有可接受的密码,所有登录尝试都会被拒绝。使用 sudo passwd youruser 设置密码,或者为面板使用其他账户。
Cockpit 可以管理 Docker 容器吗?
不可以。Cockpit 的容器页面来自 cockpit-podman,用于管理 Podman。旧版 Docker 模块多年前已被移除,目前不会恢复。如果服务运行在 Docker 中,请通过 SSH 使用版本控制中的 compose 文件进行管理,并让 Cockpit 负责管理周边系统,例如日志和磁盘。