Docker Compose 搭建服务全家桶:一个文件搞定 NAS 常用服务

zheng头像
zheng 2026-07-16 11:15
楼主

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.comvault.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.ymlservices 段里追加:

  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,立刻原地复活。

让旧手机秒变软路由:OpenWrt on Android 实战指南 Crontab从入门到自动化运维

最新回复

暂无回复,来说两句吧

发表评论

站点总访问量:2773