Docker Compose 搭建服务全家桶:一个文件搞定 NAS 常用服务
很多人在 NAS、软路由或者旧电脑上搭个人服务,装一个 Services 折腾一次,重复配 Nginx 代理、SSL 证书、数据目录。搭到最后,记忆比 DNS 还碎片化——哪个端口对应哪个服务全忘了。Docker Compose 就是来解决这个问题的:一个 YAML 文件,定义所有服务,一条命令全部启动。这篇文章给你一套可以直接复制粘贴的"服务全家桶"配置,涵盖 8 个常用服务。
Docker Compose 基础
Docker Compose 是一个 Docker 编排工具。核心概念:
| 概念 | 说明 |
|---|---|
| service | 一个容器化应用,如 Nginx、MySQL |
| volumes | 数据持久化,宿主机目录映射到容器 |
| networks | 容器间通信网络 |
| depends_on | 启动顺序依赖 |
安装(一般装 Docker 时就自带了):
# 确认 compose 可用
docker compose version
# 旧版本用 docker-compose,新版本已内置为 docker compose(注意没有横杠)
前置准备:目录结构
建一个统一的管理目录:
mkdir -p ~/docker-services
cd ~/docker-services
# 子目录结构
mkdir -p volumes/nginx/conf
mkdir -p volumes/nginx/html
mkdir -p volumes/mysql/data
mkdir -p volumes/redis/data
mkdir -p volumes/nextcloud/data
mkdir -p volumes/vaultwarden/data
mkdir -p volumes/jellyfin/{config,cache}
mkdir -p volumes/alist/data
mkdir -p volumes/nocodb/data
mkdir -p volumes/uptime-kuma/data
docker-compose.yml 全家桶
直接把下面这个文件保存为 ~/docker-services/docker-compose.yml:
version: '3.8'
services:
# ===== Nginx 反向代理 =====
nginx:
image: nginx:alpine
container_name: nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./volumes/nginx/conf:/etc/nginx/conf.d
- ./volumes/nginx/html:/usr/share/nginx/html
- ./volumes/nginx/ssl:/etc/nginx/ssl
networks:
- internal
# ===== MySQL 数据库 =====
mysql:
image: mysql:8.0
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ChangeMe123!
TZ: Asia/Shanghai
volumes:
- ./volumes/mysql/data:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password
networks:
- internal
# ===== Redis 缓存 =====
redis:
image: redis:alpine
container_name: redis
restart: always
command: redis-server --appendonly yes --requirepass ChangeMe123!
volumes:
- ./volumes/redis/data:/data
networks:
- internal
# ===== Nextcloud 私有云盘 =====
nextcloud:
image: nextcloud:stable
container_name: nextcloud
restart: always
ports:
- "8080:80"
volumes:
- ./volumes/nextcloud/data:/var/www/html
environment:
MYSQL_HOST: mysql
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: ChangeMe123!
REDIS_HOST: redis
depends_on:
- mysql
- redis
networks:
- internal
# ===== Vaultwarden 密码管理器 =====
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: always
ports:
- "8081:80"
volumes:
- ./volumes/vaultwarden/data:/data
environment:
TZ: Asia/Shanghai
SIGNUPS_ALLOWED: "false"
DOMAIN: "https://vault.yourdomain.com"
networks:
- internal
# ===== Jellyfin 媒体服务器 =====
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: always
ports:
- "8096:8096"
volumes:
- ./volumes/jellyfin/config:/config
- ./volumes/jellyfin/cache:/cache
# 映射你的媒体目录
- /path/to/movies:/media/movies
- /path/to/tv:/media/tv
environment:
TZ: Asia/Shanghai
networks:
- internal
# ===== Alist 网盘聚合 =====
alist:
image: xhofe/alist:latest
container_name: alist
restart: always
ports:
- "5244:5244"
volumes:
- ./volumes/alist/data:/opt/alist/data
environment:
TZ: Asia/Shanghai
networks:
- internal
# ===== NocoDB 在线表格 =====
nocodb:
image: nocodb/nocodb:latest
container_name: nocodb
restart: always
ports:
- "8082:8080"
volumes:
- ./volumes/nocodb/data:/usr/app/data
environment:
NC_DB: "mysql2://mysql:3306?u=root&p=ChangeMe123!&d=nocodb"
depends_on:
- mysql
networks:
- internal
# ===== Uptime Kuma 服务监控 =====
uptime-kuma:
image: louislam/uptime-kuma:latest
container_name: uptime-kuma
restart: always
ports:
- "3001:3001"
volumes:
- ./volumes/uptime-kuma/data:/app/data
networks:
- internal
networks:
internal:
driver: bridge
服务说明
| 服务 | 端口 | 用途 | 首次使用 |
|---|---|---|---|
| Nginx | 80/443 | 反向代理、SSL 终结 | 需手动配 conf |
| MySQL | 3306(内部) | 统一数据库 | docker exec mysql mysql -p |
| Redis | 6379(内部) | 缓存、Session | 已设密码 |
| Nextcloud | 8080 | 私有云盘 | 网页访问初始化 |
| Vaultwarden | 8081 | Bitwarden 自建版 | 网页注册管理员 |
| Jellyfin | 8096 | 媒体服务器 | 网页配置媒体库 |
| Alist | 5244 | 网盘聚合 | 首次 docker exec alist ./alist admin 获取密码 |
| NocoDB | 8082 | Airtable 替代 | 网页初始化 |
| Uptime Kuma | 3001 | 服务监控 | 网页注册管理员 |
启动全家桶
cd ~/docker-services
docker compose up -d
一条命令,9 个服务全部启动。-d 是后台运行。
查看状态:
docker compose ps
NAME STATUS PORTS
nginx Up 2 hours 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
mysql Up 2 hours 3306/tcp
redis Up 2 hours 6379/tcp
nextcloud Up 2 hours 0.0.0.0:8080->80/tcp
vaultwarden Up 2 hours 0.0.0.0:8081->80/tcp
jellyfin Up 2 hours 0.0.0.0:8096->8096/tcp
alist Up 2 hours 0.0.0.0:5244->5244/tcp
nocodb Up 2 hours 0.0.0.0:8082->8080/tcp
uptime-kuma Up 2 hours 0.0.0.0:3001->3001/tcp
Nginx 反向代理配置
把 9 个不同端口的服务统一到 80/443 端口,通过子域名或路径区分。
在 volumes/nginx/conf/default.conf 里写:
# Nextcloud
server {
listen 80;
server_name cloud.yourdomain.com;
location / {
proxy_pass http://nextcloud;
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;
}
}
# Vaultwarden
server {
listen 80;
server_name vault.yourdomain.com;
location / {
proxy_pass http://vaultwarden;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# Jellyfin
server {
listen 80;
server_name media.yourdomain.com;
location / {
proxy_pass http://jellyfin:8096;
proxy_set_header Host $host;
}
}
以后所有服务统一走 cloud.yourdomain.com、vault.yourdomain.com 这样的域名,不需要记端口号。
自动续期 SSL 证书(Let's Encrypt)
配合 Certbot 和 acme.sh,推荐 acme.sh + Nginx 组合:
# 在宿主机上装 acme.sh
curl https://get.acme.sh | sh
# 申请泛域名证书(需要 DNS API)
export Ali_Key="YOUR_ALI_KEY"
export Ali_Secret="YOUR_ALI_SECRET"
acme.sh --issue --dns dns_ali -d yourdomain.com -d "*.yourdomain.com"
# 安装证书到 Nginx 目录
acme.sh --install-cert -d yourdomain.com \
--key-file /path/to/docker-services/volumes/nginx/ssl/key.pem \
--fullchain-file /path/to/docker-services/volumes/nginx/ssl/fullchain.pem \
--reloadcmd "docker exec nginx nginx -s reload"
acme.sh 会自动创建 cron 任务定期续期,证书过期前 60 天自动更新。全程零人工干预。
日常运维命令
# 全部停止(数据不丢)
docker compose down
# 全部重启
docker compose restart
# 更新所有镜像到最新版本
docker compose pull && docker compose up -d
# 只重启某一个服务
docker compose restart nginx
# 查看日志
docker compose logs -f --tail=50 mysql
# 备份 MySQL 数据
docker exec mysql mysqldump -p ChangeMe123! --all-databases > backup.sql
添加新服务
比如想加一个 Portainer(Docker 可视化管理):
在 docker-compose.yml 的 services 段里追加:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: always
ports:
- "9000:9000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./volumes/portainer/data:/data
networks:
- internal
然后:
docker compose up -d portainer
只启动新增的服务,不影响已有服务。在线热插拔,不需要全局重启。
常见问题
Q:为什么不用 Portainer 这种图形化界面?
可以用,本文没列入只是因为 Portainer 是管理工具而不是业务服务。你觉得需要就加一行,位置随意。
Q:MySQL 密码明写了不安全吧?
是的。生产环境建议用 .env 文件:
# docker-compose.yml
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
# .env 文件(记得加入 .gitignore)
MYSQL_ROOT_PASSWORD=StrongPasswordHere
本文直接写在 yml 里是为了方便演示和复制。实际部署请改成 env 引用。
Q:这些服务吃多少内存?
9 个服务全部启动后,内存占用:
| 服务 | 内存 |
|---|---|
| Nginx | 10 MB |
| MySQL | 300 MB |
| Redis | 5 MB |
| Nextcloud | 150 MB |
| Vaultwarden | 30 MB |
| Jellyfin | 200 MB(空闲) |
| Alist | 30 MB |
| NocoDB | 150 MB |
| Uptime Kuma | 60 MB |
| 合计 | 约 1 GB |
也就是说,一台 2GB 的 VPS 或旧电脑就能跑这套全家桶。
一个 YAML 文件,9 个服务,一条命令。以后再也不用翻开小本本找"那个服务开的哪个端口"。所有配置、数据、备份都在一个目录下,迁移的时候打包整个 docker-services 目录,scp 到新机器,docker compose up -d,立刻原地复活。