老实说,写这篇文章的动机,来自于最近在好几个技术社群里看到的同一幕——新手买了个VPS,装好宝塔跑了个WordPress,然后就不知道还能干什么了。
你看,这其实挺可惜的。
一台VPS,尤其是现在2026年,2核2G的KVM VPS已经卷到一个月十几二十块钱(RackNerd、CloudCone这些厂商打得火热)。但大部分人买回来,就只装个LNMP跑一个博客,CPU常年跑在3%以下,内存还剩一大半——这不就是拿着跑车去买菜吗?
正好,最近CSDN、掘金上Docker相关的内容火得一塌糊涂。前两天我看CSDN热榜,排名第一的就是Docker部署相关的文章。这让我觉得,是时候聊一聊怎么用Docker把你的VPS真正用起来这个话题了。
目录
- 为什么2026年你必须在VPS上用Docker?
- 第一步:VPS上安装Docker的正确姿势
- 第二步:用Docker Compose编排你的第一个应用
- 第三步:让服务跑起来——端口映射、数据持久化、自动重启
- 第四步:用NPM(Nginx Proxy Manager)统一管理域名和SSL
- 一步到位:一个Docker Compose模板管所有
- 常见坑和应对方案
- 总结
为什么2026年你必须在VPS上用Docker?
先说说我自己的经历。
2022年那会儿,我还是个"裸机党"。买一台VPS,apt install nginx,apt install mysql,apt install php——一把梭把环境装好。看起来挺爽对吧?
问题在后面。
有一次我要部署第二个网站,需要PHP 8.0,但第一个网站用的PHP 7.4。你怎么办?两个PHP版本共存?我当时查了一下午资料,最后搞了个极其丑陋的多端口方案。后来又遇到MySQL 5.7和MySQL 8.0同时需要的情况——那次我差点把服务器重装了。
Docker解决的就是这个问题。
每一个应用都带着它的完整运行环境,互不干扰。你要PHP 7.4?docker pull。你要PHP 8.2?docker pull。它们可以在同一台VPS上和平共处,就像两套独立的房子,共享水电但互不打扰。
试想一下,如果你是一个"一人公司"的独立开发者(这个词最近在掘金上特别火),你的VPS上可能要同时跑:
- 一个个人博客(Nginx + PHP + MySQL)
- 一个API服务(Node.js + Redis)
- 一个AI模型代理(Python + FastAPI)
- 一个监控面板(Grafana + Prometheus)
没有Docker,光环境冲突就能让你崩溃。有了Docker,这些就是一个docker-compose.yml文件的事。
第一步:VPS上安装Docker的正确姿势
不管你买的是哪家的VPS——RackNerd、搬瓦工、CloudCone还是国内厂商——安装Docker的过程基本一样。
SSH登录你的VPS,然后执行:
curl -fsSL https://get.docker.com | bash
就这么一行。不要自己配源,不要自己apt install docker.io。 官方脚本会自动检测你的系统版本,配置好正确的仓库源。
装完之后,把当前用户加入docker组,省得每次都要sudo:
sudo usermod -aG docker $USER
# 退出SSH重新登录生效
验证一下:
docker --version
docker compose version
如果看到版本号,恭喜你,你的VPS已经具备了现代应用部署的能力。
供你参考: 如果你在国内VPS上遇到拉取镜像慢的问题,可以配置阿里云或中科大的镜像加速器。在 /etc/docker/daemon.json 中写入:
{
"registry-mirrors": ["https://docker.m.daocloud.io"]
}
然后 systemctl restart docker 搞定。
第二步:用Docker Compose编排你的第一个应用
单用 docker run 不是不行,但相信我,用过Docker Compose你就回不去了。
创建一个项目目录:
mkdir -p ~/myapp && cd ~/myapp
创建一个 docker-compose.yml:
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
restart: always
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: my_secret_pwd
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
restart: always
volumes:
db_data:
然后在当前目录下创建一个 html/index.html,写点内容:
<h1>Hello from Docker on VPS!</h1>
启动:
docker compose up -d
打开浏览器访问 http://你的VPSIP:8080——看到页面了没?
整个过程不到5分钟。 如果不用Docker,光装Nginx和MySQL你就要折腾至少半小时,还得处理各种版本兼容问题。
第三步:让服务跑起来——端口映射、数据持久化、自动重启
很多新手有个误区:觉得Docker容器是"临时的",数据放进去随时会丢。
这不是Docker的问题,是你没做数据持久化。
Docker提供了三种持久化方式:
| 方式 | 适用场景 | 示例 |
|---|---|---|
| bind mount | 开发调试、配置文件 | ./html:/usr/share/nginx/html |
| volume | 数据库等生产数据 | db_data:/var/lib/mysql |
| tmpfs | 临时数据(重启即丢) | 很少用 |
我的推荐: 数据库用volume,应用代码用bind mount。
另外三个必加的配置项:
restart: always # 服务器重启后容器自动启动
restart: unless-stopped # 除非手动停止,否则自动重启(推荐)
network_mode: bridge # 默认,容器间通过名称通信
为什么不推荐 --net=host? 安全。bridge模式下容器有独立的网络栈,就算某个容器被攻破了,攻击者也不能直接访问宿主机的全部端口。
第四步:用NPM(Nginx Proxy Manager)统一管理域名和SSL
好,现在你VPS上跑了好几个容器,每个容器占一个端口——8080、3000、5000……难不成你要告诉用户"访问我的网站,记得加端口号"?
当然不是。
你需要一个反向代理。而Nginx Proxy Manager(NPM)是目前最省事的方案——有Web界面,点几下就能配好域名 + SSL证书,而且是Docker一键部署的。
version: '3.8'
services:
npm:
image: jc21/nginx-proxy-manager:latest
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "81:81" # 管理界面
volumes:
- npm_data:/data
- npm_ssl:/etc/letsencrypt
restart: unless-stopped
volumes:
npm_data:
npm_ssl:
启动后访问 http://你的VPSIP:81,默认账号 admin@example.com / changeme。
进去之后你想干嘛?
- 添加一个域名
blog.example.com - 指向
web:80(注意这里是容器名,不是IP) - 一键申请Let's Encrypt SSL证书
- 打开强制HTTPS
全部鼠标操作,不用手动配Nginx配置文件的滋味,你试过一次就回不去了。 是不是?
而且,你后续每新增一个服务,只需要在NPM后台加一条转发规则就行了——完全不用碰服务器配置。
一步到位:一个Docker Compose模板管所有
说了这么多,给你一个可以直接用的模板。这是一个我在用的"一人公司"级VPS部署方案:
version: '3.8'
networks:
app_net:
driver: bridge
services:
# --- 反向代理 ---
npm:
image: jc21/nginx-proxy-manager:latest
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
- npm_data:/data
- npm_ssl:/etc/letsencrypt
networks:
- app_net
restart: unless-stopped
# --- 博客(WordPress) ---
wordpress:
image: wordpress:6.7-php8.2-apache
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: wp_db
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: wp_pass
WORDPRESS_DB_NAME: wp_db
volumes:
- wp_data:/var/www/html
networks:
- app_net
restart: unless-stopped
wp_db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root_pass
MYSQL_DATABASE: wp_db
MYSQL_USER: wp_user
MYSQL_PASSWORD: wp_pass
volumes:
- wp_db_data:/var/lib/mysql
networks:
- app_net
restart: unless-stopped
# --- API服务(Node.js示例) ---
api:
image: node:20-alpine
working_dir: /app
volumes:
- ./api:/app
command: sh -c "npm install && node server.js"
ports:
- "3000:3000"
networks:
- app_net
restart: unless-stopped
volumes:
npm_data:
npm_ssl:
wp_data:
wp_db_data:
你看,一个文件,三个服务,各自独立又互相联通。 你甚至可以把这个文件放在Git仓库里,换一台VPS直接 docker compose up -d 就全跑起来了——这才是真正的"基础设施即代码"。
常见坑和应对方案
我踩过的坑,你就不用再踩了。
坑1:VPS内存太小,跑不动多个容器
这是最常被问的问题。2026年的入门级VPS一般是1G内存。Docker本身占100MB左右,一个Nginx占50MB,一个MySQL占300MB——看起来还行对吧?但如果你要跑3-4个服务,1G内存确实不够用。
解决方案:
- 选2G内存以上的VPS(RackNerd的AMD Ryzen系列2G内存大概$20/年左右)
- 用 --memory="256m" 限制单个容器内存
- 非核心服务用SQLite替代MySQL
坑2:容器日志撑爆磁盘
默认情况下Docker会无限保留容器日志。跑一个月,/var/lib/docker可能就被日志撑爆了。
解决方案: 在 docker-compose.yml 里加上日志限制:
services:
any_service:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
坑3:忘记配置防火墙
装了Docker之后,iptables会被Docker接管。如果你之前用ufw配了防火墙规则,可能会出现Docker容器能绕过防火墙的情况。
解决方案:
# 在 /etc/ufw/after.rules 中配置Docker网段规则
# 或者简单粗暴:只让Docker暴露你指定的端口
坑4:用便宜VPS跑生产数据库
这里我必须直说了——20块钱一个月的VPS,它的磁盘IO和稳定性是不足以跑生产数据库的。 你要是做个个人博客或side project,没问题。但如果是面向客户的产品,数据库至少要用云厂商的RDS,或者买NVMe SSD VPS。
这不是Docker的问题,这是成本认知的问题。
总结
回过头来看,2026年的VPS市场已经卷到了一个非常夸张的程度。$2-3一个月就能拿到一台性能不错的KVM VPS,配上Docker,你完全可以用一杯奶茶的价格撑起一个"一人公司"的技术栈。
最后给你几个建议,供你参考:
- 新手入门:买一台2G内存以上的VPS,装Docker,用NPM管理域名,从WordPress或静态博客开始
- 进阶玩家:学Docker Compose,把你的服务都编排起来,配上Grafana监控
- 高级玩法:用Docker Swarm或K3s做集群,不过——说真的,个人用不到这个级别
这几年我见过太多人,买了一台VPS就只装了个面板跑博客,然后吃灰。其实只要你愿意花一个下午的时间把Docker跑起来,你的VPS能干的事情会多得多——CI/CD、AI代理、文件同步、开发环境、VPN、监控系统……
别让你的VPS闲着,也别让你的技术止步于装面板。
(全文完)
评论 (0)