Debian 12 VPS Docker 面板选择与安全部署教程

字数3866阅读约 10 分钟访问--

Debian 12 VPS Docker 面板选择与安全部署教程

这篇笔记整理一台 Debian 12 新 VPS 从初始化加固到 Docker 应用管理的完整路线。目标是:先保证 SSH 不被锁死,再完成基础安全配置,然后安装 Docker,最后用 Dockge 管理 Compose 应用,并用 Nginx Proxy Manager 统一处理域名和 HTTPS。

推荐的最终架构是:

公网入口:
  80/tcp
  443/tcp
 
SSH:
  自定义端口,例如 8622
  禁止 root 登录
  禁止密码登录
  只允许密钥登录
 
安全组件:
  UFW
  fail2ban
  unattended-upgrades
 
Docker 管理:
  Docker Engine
  Docker Compose Plugin
  Dockge
 
反向代理:
  Nginx Proxy Manager
  公共 Docker 网络 npm_proxy

适用场景

这套方案适合以下 VPS 使用场景:

  • 准备用 Docker Compose 长期部署多个自建应用。
  • 希望有一个轻量 Web 面板管理 Compose 文件和容器日志。
  • 想用域名访问应用,而不是记住一堆端口。
  • 希望管理面板不直接裸露到公网。
  • 想在 Debian 12 上先完成基础安全加固,再部署服务。

如果只是临时测试一两个容器,纯命令行也可以;如果准备长期运行博客、Alist、Uptime Kuma、Vaultwarden、数据库、代理服务等,Dockge + Nginx Proxy Manager 会更好维护。

总体部署顺序

建议按这个顺序执行:

1. 保留当前 SSH 连接,避免配置错误后失联
2. 修复 hostname / sudo warning
3. 更新系统并安装基础工具
4. 配置 UFW 防火墙
5. 修改 SSH 配置
6. 安装 fail2ban
7. 开启自动安全更新
8. 安装 Docker Engine 和 Compose Plugin
9. 安装 Dockge
10. 安装 Nginx Proxy Manager
11. 创建公共 Docker 网络 npm_proxy
12. 后续应用统一接入 npm_proxy,由 NPM 做域名反代

1. 保留当前 SSH 安全窗口

开始加固前,不要关闭当前 SSH 窗口。后续每次修改 SSH 或防火墙,都新开一个终端测试登录。

例如计划把 SSH 改到 8622 端口后,本地 PowerShell 测试:

ssh -p 8622 fage@你的服务器IP

新窗口确认能登录后,再关闭旧窗口或删除旧端口规则。这样即使某一步配置错误,也还有一个可用会话可以救回服务器。

2. 修复 sudo hostname 警告

如果执行 sudo 时出现类似提示:

sudo: unable to resolve host imztb

先检查主机名和 hosts:

hostname
cat /etc/hostname
cat /etc/hosts

如果 hostname 是 imztb,编辑 /etc/hosts

sudo nano /etc/hosts

确保至少包含:

127.0.0.1       localhost
127.0.1.1       imztb

测试:

sudo whoami

如果输出 root 且不再出现 warning,说明修复完成。

3. 更新系统并安装基础工具

sudo apt update
sudo apt upgrade -y
sudo apt install -y curl wget git vim nano ca-certificates gnupg lsb-release unzip htop

这些工具会在后续下载 Docker 源、编辑配置、检查资源和排障时用到。

4. 配置 UFW 防火墙

安装 UFW:

sudo apt install -y ufw

默认拒绝入站,允许出站:

sudo ufw default deny incoming
sudo ufw default allow outgoing

放行新的 SSH 端口:

sudo ufw allow 8622/tcp

如果后续要部署网站或反向代理,放行 HTTP 和 HTTPS:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

启用防火墙:

sudo ufw enable

查看状态:

sudo ufw status verbose

确认至少有:

8622/tcp ALLOW IN
80/tcp   ALLOW IN
443/tcp  ALLOW IN

如果还没有确认新 SSH 端口能正常登录,可以临时保留 22:

sudo ufw allow 22/tcp

确认 8622 登录成功后再删除:

sudo ufw delete allow 22/tcp

5. 修改 SSH 加固配置

编辑 SSH 服务端配置:

sudo nano /etc/ssh/sshd_config

推荐配置:

Port 8622
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
UsePAM yes
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
MaxAuthTries 3

关键参数说明:

  • Port 8622:修改 SSH 监听端口,减少默认端口扫描噪音。
  • PermitRootLogin no:禁止 root 直接登录。
  • PasswordAuthentication no:禁止密码登录,只使用密钥登录。
  • PubkeyAuthentication yes:启用公钥认证。
  • KbdInteractiveAuthentication no:关闭键盘交互式认证,避免绕过密码登录策略。
  • UsePAM yes:保留 PAM 会话管理能力,Debian 上通常建议保持开启。
  • X11Forwarding no:关闭 X11 转发,服务器场景一般用不到。
  • ClientAliveInterval 300:每 300 秒检查一次客户端连接。
  • ClientAliveCountMax 2:连续 2 次无响应后断开空闲连接。
  • MaxAuthTries 3:限制单次连接认证尝试次数。

检查 SSH 配置语法:

sudo sshd -t

无输出表示语法正常。然后重载 SSH:

sudo systemctl reload ssh

检查监听端口:

sudo ss -lntp | grep ssh

新开本地终端测试:

ssh -p 8622 fage@你的服务器IP

确认能登录后,再考虑删除 22 端口的防火墙放行。

6. 安装 fail2ban

fail2ban 可以根据登录失败日志自动封禁恶意 IP。

sudo apt install -y fail2ban

创建配置:

sudo nano /etc/fail2ban/jail.local

写入:

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
 
[sshd]
enabled = true
port = 8622
filter = sshd
logpath = %(sshd_log)s
maxretry = 5

启动并设置开机自启:

sudo systemctl enable --now fail2ban

检查状态:

sudo fail2ban-client status
sudo fail2ban-client status sshd

7. 开启自动安全更新

安装 unattended-upgrades:

sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure unattended-upgrades

弹窗选择 Yes。然后检查服务:

systemctl status unattended-upgrades

这一步可以让系统自动安装安全更新,适合长期运行的 VPS。

8. 安装 Docker Engine 和 Compose Plugin

Dockge 本身也是 Docker 应用,所以使用 Dockge 之前必须先安装 Docker。

创建 keyrings 目录并导入 Docker GPG key:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

添加 Docker 官方源:

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

安装 Docker:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

启动并开机自启:

sudo systemctl enable --now docker

让普通用户可以执行 Docker 命令:

sudo usermod -aG docker fage

执行后退出 SSH 并重新登录,让用户组生效。然后测试:

docker version
docker compose version

9. Docker 与 UFW 的安全注意事项

Docker 会直接操作 iptables,有时可能绕过 UFW 的入站规则。因此管理面板不要随便用下面这种方式直接暴露到公网:

ports:
  - "5001:5001"

更推荐把管理端口只绑定本机:

ports:
  - "127.0.0.1:5001:5001"

然后从本地电脑通过 SSH 隧道访问:

ssh -p 8622 -L 5001:127.0.0.1:5001 fage@服务器IP

浏览器打开:

http://127.0.0.1:5001

这样管理面板不会直接暴露公网,安全性更高。

10. Docker 面板选择建议

常见选择大致可以分为三类:

Dockge:
  轻量,专注 Docker Compose,适合个人 VPS 管理多个 compose 应用。
 
Portainer:
  功能更全,但更重,适合更复杂的 Docker 管理场景。
 
纯命令行:
  最透明、依赖少,但维护多个应用时不如 Web 面板直观。

如果目标是在一台 VPS 上部署多个自建服务,推荐使用 Dockge。它可以集中管理 compose 应用、在线编辑 compose.yaml、启动停止服务、查看日志,比纯命令行更直观,也比 Portainer 更轻。

可以把关系理解为:

Docker Engine = 地基
Docker Compose = 应用编排工具
Dockge = Docker Compose 的网页管理面板

Dockge 不能替代 Docker,它只是 Docker 之上的管理工具。

11. 安装 Dockge

创建目录:

sudo mkdir -p /opt/dockge
sudo mkdir -p /opt/stacks
sudo chown -R fage:fage /opt/dockge /opt/stacks
cd /opt/dockge

创建 compose.yaml

nano compose.yaml

写入:

services:
  dockge:
    image: louislam/dockge:1
    container_name: dockge
    restart: unless-stopped
    ports:
      - "127.0.0.1:5001:5001"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/app/data
      - /opt/stacks:/opt/stacks
    environment:
      - DOCKGE_STACKS_DIR=/opt/stacks

启动:

docker compose up -d

查看状态:

docker compose ps
docker logs dockge

本地 PowerShell 开 SSH 隧道:

ssh -p 8622 -L 5001:127.0.0.1:5001 fage@服务器IP

浏览器打开:

http://127.0.0.1:5001

首次进入会要求创建管理员账号。密码一定要足够强。

12. FinalShell 粘贴 YAML 的建议

FinalShell 里直接往 nano 粘贴大段 YAML,容易出现缩进、换行、特殊字符错乱。更稳的方式是用 here-document 写文件。

例如重写 Dockge 的 compose:

cat > /opt/dockge/compose.yaml <<'EOF'
services:
  dockge:
    image: louislam/dockge:1
    container_name: dockge
    restart: unless-stopped
    ports:
      - "127.0.0.1:5001:5001"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/app/data
      - /opt/stacks:/opt/stacks
    environment:
      - DOCKGE_STACKS_DIR=/opt/stacks
EOF

cat <<'EOF' 的好处是内容会原样写入文件,不容易被 shell 展开变量,也不依赖 nano 的粘贴行为。

如果仍想用 nano,建议先在本地编辑器里整理好 YAML,再少量分段粘贴,并用下面命令检查最终文件:

sed -n '1,120p' /opt/dockge/compose.yaml

13. 规划 Docker 目录

推荐目录:

/opt/dockge
  compose.yaml
  data/
 
/opt/stacks
  nginx-proxy-manager/
    compose.yaml
  alist/
    compose.yaml
  uptime-kuma/
    compose.yaml
  vaultwarden/
    compose.yaml

Dockge 管理 /opt/stacks 下的各个应用,每个应用一个目录,方便备份和迁移。

14. 部署 Nginx Proxy Manager

Nginx Proxy Manager,简称 NPM,用来把域名转发到 Docker 内部应用。

例如:

https://alist.example.com -> http://alist:5244
https://kuma.example.com  -> http://uptime-kuma:3001
https://dockge.example.com -> http://dockge:5001

先确认防火墙放行网站端口:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

不要把 NPM 管理端口 81 直接开放到公网。推荐让 80/443 对公网开放,81 只绑定本机。

创建公共 Docker 网络:

docker network create npm_proxy

如果提示已经存在,可以忽略。

在 Dockge 里创建应用,名称建议为:

nginx-proxy-manager

compose.yaml 示例:

services:
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "127.0.0.1:81:81"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - npm_proxy
 
networks:
  npm_proxy:
    external: true

这个配置里:

- "80:80"
- "443:443"

用于公网访问网站。

- "127.0.0.1:81:81"

表示 NPM 后台只允许服务器本机访问。

15. 访问 NPM 后台

因为 81 端口只绑定本机,所以需要 SSH 隧道:

ssh -p 8622 -L 8181:127.0.0.1:81 fage@服务器IP

保持这个窗口不要关,浏览器打开:

http://127.0.0.1:8181

NPM 默认账号:

Email: [email protected]
Password: changeme

首次登录后立即修改邮箱和密码。

16. 配置域名 DNS

假设域名是 example.com,可以添加这些 A 记录:

类型    主机记录    值
A       npm         你的服务器IP
A       dockge      你的服务器IP
A       app         你的服务器IP

也可以添加泛解析:

类型    主机记录    值
A       *           你的服务器IP

这样以后 alist.example.comkuma.example.comvault.example.com 都可以在 NPM 里单独配置。

17. 后续应用如何接入 NPM

只要应用需要通过域名访问,就建议加入公共网络:

networks:
  - npm_proxy

文件底部加:

networks:
  npm_proxy:
    external: true

例如 Alist:

services:
  alist:
    image: xhofe/alist:latest
    container_name: alist
    restart: unless-stopped
    volumes:
      - ./data:/opt/alist/data
    networks:
      - npm_proxy
 
networks:
  npm_proxy:
    external: true

NPM 里配置:

Domain Names: alist.example.com
Scheme: http
Forward Hostname / IP: alist
Forward Port: 5244

即使 Compose 没有写 ports,NPM 和应用在同一个 Docker 网络里,也可以通过容器名访问。这是最推荐的方式。

18. ports 要不要绑定 127.0.0.1

按用途判断。

NPM 入口服务

NPM 必须开放公网的 80 和 443:

ports:
  - "80:80"
  - "443:443"
  - "127.0.0.1:81:81"

81 是后台管理端口,建议只绑定 127.0.0.1

管理面板

Dockge、Portainer、NPM 后台、Uptime Kuma 管理页这类服务,如果还想保留 SSH 隧道访问,建议:

ports:
  - "127.0.0.1:5001:5001"

这样公网不能直接访问端口。

普通 Web 应用

如果应用只通过 NPM 域名访问,通常不需要写 ports,只要加入 npm_proxy 网络即可。

需要公网直连的服务

只有确实需要公网直连时,才开放:

ports:
  - "0.0.0.0:端口:容器端口"

这类服务要特别确认认证、访问限制和防火墙策略。

记忆规则:

NPM:开放 80、443;81 绑 127.0.0.1
管理面板:端口尽量绑 127.0.0.1
普通应用:不写 ports,只加入 npm_proxy
需要公网直连的服务:才开放 0.0.0.0:端口

19. 是否要用域名访问 Dockge

可以用域名访问 Dockge,但要谨慎。

Dockge 挂载了:

/var/run/docker.sock:/var/run/docker.sock

这意味着 Dockge 拥有很高的 Docker 控制权限,基本等价于服务器管理能力。

如果要配置:

https://dockge.example.com

至少建议:

  • Dockge 密码必须强。
  • NPM 给 dockge.example.com 添加 Access List。
  • 最好限制 IP 或增加 Basic Auth。
  • 不要把 5001 端口公网开放。
  • 保留 SSH 隧道作为备用访问方式。

Dockge 的 compose 可以改成:

services:
  dockge:
    image: louislam/dockge:1
    container_name: dockge
    restart: unless-stopped
    ports:
      - "127.0.0.1:5001:5001"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/app/data
      - /opt/stacks:/opt/stacks
    environment:
      - DOCKGE_STACKS_DIR=/opt/stacks
    networks:
      - npm_proxy
 
networks:
  npm_proxy:
    external: true

然后重新应用:

cd /opt/dockge
docker compose up -d

NPM 里添加 Proxy Host:

Domain Names: dockge.example.com
Scheme: http
Forward Hostname / IP: dockge
Forward Port: 5001

SSL 里勾选:

Request a new SSL Certificate
Force SSL
HTTP/2 Support

20. Dockge 域名访问 502 的排查

如果访问 dockge.example.com 出现 502 Bad Gateway,说明浏览器已经访问到 NPM,但 NPM 转发不到 Dockge 容器。

常见原因:

1. Dockge 没有真正加入 npm_proxy 网络
2. NPM 里 Forward Hostname 写错
3. NPM 里 Forward Port 写错
4. Dockge 容器名不是 dockge
5. Dockge 服务本身没正常启动

检查 Dockge 容器状态

docker ps

应该能看到:

dockge
nginx-proxy-manager

如果没有 dockge,查看日志:

docker logs dockge --tail=50

检查 Docker 网络

docker inspect dockge --format '{{json .NetworkSettings.Networks}}'

正常情况下能看到 npm_proxy

也可以检查整个网络:

docker network inspect npm_proxy

输出里应该同时有:

nginx-proxy-manager
dockge

如果只有 NPM 没有 Dockge,就是 Dockge 没接入网络。

检查 Dockge compose

Dockge 的 compose 需要同时包含:

networks:
  - npm_proxy

以及底部:

networks:
  npm_proxy:
    external: true

修改后要执行:

cd /opt/dockge
docker compose up -d

只重启 Docker 服务不一定会重新应用 compose 网络配置。

检查 NPM Proxy Host

NPM 中应填写:

Domain Names: dockge.example.com
Scheme: http
Forward Hostname / IP: dockge
Forward Port: 5001

不要填:

127.0.0.1
localhost
服务器IP
https
443

对 NPM 容器来说,127.0.0.1 指的是 NPM 容器自己,不是宿主机,也不是 Dockge。

在 NPM 容器中测试

进入 NPM 容器:

docker exec -it nginx-proxy-manager sh

测试访问 Dockge:

wget -S -O- http://dockge:5001

如果正常,会看到 HTML 内容。

如果提示:

bad address 'dockge'

说明 NPM 解析不到 Dockge,通常是 Docker 网络没打通。

如果提示:

connection refused

说明找到了 Dockge,但 Dockge 的 5001 没监听或服务异常。

测试完退出:

exit

临时快速修复

如果只想先恢复访问,可以在 NPM 里临时填:

Scheme: http
Forward Hostname / IP: 172.17.0.1
Forward Port: 5001

前提是 Dockge 仍然有:

ports:
  - "127.0.0.1:5001:5001"

但这个方式不如 Docker 网络稳定。长期推荐使用:

Forward Hostname / IP: dockge
Forward Port: 5001

21. 常用检查命令

SSH:

sudo ss -lntp | grep ssh
sudo systemctl status ssh

防火墙:

sudo ufw status numbered

fail2ban:

sudo fail2ban-client status sshd

Docker:

docker ps
docker logs 容器名
docker compose ps

端口监听:

sudo ss -lntp

系统资源:

htop
df -h
free -h

总结

Debian 12 VPS 自建服务的关键不是先装哪个面板,而是先把基础安全做好。推荐先完成 SSH、UFW、fail2ban 和自动安全更新,再安装 Docker。应用管理层可以选择 Dockge,它适合个人 VPS 管理多个 Compose 应用;域名访问层用 Nginx Proxy Manager,后续普通应用统一加入 npm_proxy 网络,由 NPM 通过容器名转发。

管理面板类服务不要直接裸露公网。更稳妥的做法是:端口绑定 127.0.0.1,平时用 SSH 隧道访问;如果要用域名访问,也要加 HTTPS、强密码、Access List 或 IP 限制,并保留隧道作为备用入口。