2026 年 Docker Compose 自建服務入門:打造個人私有雲
MYSQL_HOST: nextcloud-db
REDIS_HOST: nextcloud-redis
POSTGRES_USER: immich
POSTGRES_DB: immich
TZ: Asia/Taipei
volumes:
- ./pgdata:/var/lib/postgresql/data
immich-redis:
image: redis:alpine
container_name: immich-redis
restart: unless-stopped
networks:
proxy-net:
external: true
Immich 對記憶體的需求比 Vaultwarden 高,機器學習服務(人臉辨識、智慧搜尋)建議至少 4GB 記憶體。如果你的主機只有 8GB,可以暫時關閉 immich-machine-learning,改用外部 API 或在初次索引完成後再開啟。
還有一個實務重點:照片的硬碟容量一定要留足。手機拍照的畫質越來越高,一支手機一年產出 50GB 到 100GB 很常見。建議直接把照片目錄掛載到外接硬碟或 NAS。
4-6 Jellyfin:家庭媒體中心
Jellyfin 是完全開源、免費、無廣告、無追蹤的媒體伺服器。影片放在自己的硬碟,搭配手機、電視盒、電腦的 App 播放,體驗跟商業串流幾乎無異。
# /srv/docker/jellyfin/compose.yaml
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
environment:
TZ: Asia/Taipei
JELLYFIN_PublishedServerUrl: "https://media.example.com"
volumes:
- ./config:/config
- ./cache:/cache
- /mnt/media/movies:/media/movies:ro
- /mnt/media/tv:/media/tv:ro
networks:
- proxy-net
devices:
- /dev/dri:/dev/dri # 啟用 Intel 內顯硬體轉碼
networks:
proxy-net:
external: true
devices: /dev/dri 這行是讓 Intel 內顯可以協助影片轉碼,大幅降低 CPU 負載。如果你用的是 N100 或更新的處理器,這項設定能讓同時播放多路 4K 影片成為可能。AMD 顯卡則使用 /dev/dri/renderD128,NVIDIA 需要額外安裝 runtime。
4-7 Uptime Kuma:服務監控與通知
當你跑的服務變多,「某個服務偷偷掛掉」就變成常態。Uptime Kuma 可以定期檢查每個服務的狀態,一旦異常就透過 Telegram、Discord、Email 或 Webhook 通知你。
# /srv/docker/uptime-kuma/compose.yaml
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
environment:
TZ: Asia/Taipei
UPTIME_KUMA_DISABLE_STATS: "true"
volumes:
- ./data:/app/data
networks:
- proxy-net
networks:
proxy-net:
external: true
啟動後建立管理員帳號,接著新增監控項目。建議至少監控:反向代理本身、Nextcloud、Immich、Vaultwarden 的首頁回應碼。監控間隔設 60 秒就很夠用,設太短只會製造無意義的請求。
五、資料安全:備份、更新與災難復原
前面裝得再漂亮,沒有備份就等於零。這一段是整篇文章最重要、也最常被忽略的部分。
5-1 「3-2-1 備份原則」的實際應用
3-2-1 原則指的是:至少 3 份資料、存在 2 種不同媒介、其中 1 份放在異地。對自建私有雲來說,可以這樣落地:
第 1 份:主機上的原始資料。
很多人只做第 2 份,結果家裡遭竊、淹水或火災時,兩份一起消失。異地備份是必要成本,但雲端冷儲存很便宜,1TB 一年通常不到一千元。
5-2 用 Restic 建立自動化加密備份
Restic 是輕量、跨平台、支援增量與加密的備份工具,非常適合 Docker 環境。
# 安裝 restic
sudo apt install -y restic
初始化本地備份庫
export RESTIC_REPOSITORY=/mnt/backup/restic
export RESTIC_PASSWORD="你的備份密碼"
restic init
執行備份
restic backup /srv/docker --exclude-caches
查看快照
restic snapshots
建立每日自動執行的 systemd timer:
# /etc/systemd/system/restic-backup.service
[Unit]
Description=Restic Backup
After=docker.service
[Service]
Type=oneshot
Environment="RESTIC_REPOSITORY=/mnt/backup/restic"
Environment="RESTIC_PASSWORD=你的備份密碼"
ExecStart=/usr/bin/restic backup /srv/docker --exclude-caches
ExecStartPost=/usr/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Daily Restic Backup
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl enable --now restic-backup.timer
資料庫類的服務(Nextcloud、Immich)在備份前最好先傾倒出 SQL 檔,否則直接複製資料庫檔案可能得到不一致的狀態。可以在 compose 中加入每日執行的資料庫傾倒腳本,或使用服務內建的匯出功能。
5-3 Watchtower 自動更新的風險與設定
很多人推薦用 Watchtower 自動更新容器映像,但我必須說清楚:自動更新是一把雙面刃。好處是安全修補不落後,壞處是某次更新可能讓服務無法啟動,而你可能三天後才發現。
比較穩健的做法是:
使用 Watchtower 的監控模式(只通知、不更新),先觀察一段時間。
針對資料庫或核心服務,採用「手動更新 + 更新前快照」的方式。
services:
watchtower:
image: containrrr/watchtower:latest
container_name: watchtower
restart: unless-stopped
environment:
TZ: Asia/Taipei
WATCHTOWER_MONITOR_ONLY: "true"
WATCHTOWER_NOTIFICATIONS: shoutrrr
WATCHTOWER_NOTIFICATION_URL: "telegram://token@telegram?chats=chatid"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
更新前務必先看官方發布說明(Release Notes),確認有沒有 breaking change,尤其是大版號更新(例如 v1 → v2)。
5-4 災難復原演練:一定要做一次
備份沒有驗證過,就等於沒有備份。找一個週末,做一次完整的復原演練:
把主機上的某個服務目錄改名(模擬損毀)。
從 restic 還原該目錄。
重新 docker compose up -d。
確認服務資料完整、可登入、檔案存在。
這個過程會讓你發現很多「以為有備份、其實漏掉」的東西,例如資料庫密碼、憑證檔案、環境變數。演練一次,勝過讀十篇教學。
六、效能調校與常見問題排查
服務跑起來只是開始,接下來要讓它跑得穩、跑得久。
6-1 資源限制與系統調校
Docker 預設不限制容器資源,某個失控的容器可能吃光記憶體導致整台主機癱瘓。加上限制:
services:
immich-server:
...其他設定
deploy:
resources:
limits:
cpus: "2.0"
memory: 2G
reservations:
memory: 512M
另外幾個實用的系統層級調校:
sudo sysctl vm.swappiness=10,讓系統優先使用記憶體而不是交換檔。開啟 BBR 擁塞控制:對外服務的網路吞吐會更順。
把資料庫目錄放在 SSD:HDD 上的資料庫效能會讓你懷疑人生。
docker image prune -a,尤其是經常更新的服務。6-2 五個最常見的錯誤與解法
問題一:502 Bad Gateway。反向代理找不到後端服務。檢查三件事:容器是否在執行(docker compose ps)、轉發的主機名稱是否正確、兩個容器是否在同一個網路。最常見的原因是反向代理在 proxy-net,但目標服務忘了加入。
問題二:權限錯誤(Permission denied)。容器內的使用者 UID 與主機目錄擁有者不符。解法是查詢容器使用者的 UID(docker compose exec 服務名 id),然後在主機上 chown -R 對應UID:對應GID ./data。
問題三:YAML 縮排錯誤。錯誤訊息通常是 yaml: line X: did not find expected key。解法是把內容貼到 YAML 驗證工具檢查,或直接用 docker compose config 驗證語法。
問題四:連接埠已被佔用。錯誤訊息是 bind: address already in use。用 sudo ss -tulpn | grep :端口號 找出佔用者,把 compose 檔案的主機端口改掉即可。
問題五:服務啟動後馬上退出。用 docker compose logs 服務名 看日誌。九成是環境變數缺少、資料庫連不上、或資料目錄權限不對。
6-3 安全強化清單
服務上線後,逐項檢查:
所有對外服務都走 HTTPS,憑證自動續期已設定。
SSH 改用金鑰登入,關閉密碼驗證與 root 登入。
安裝 fail2ban,防止暴力破解。
重要帳號全部開啟兩步驟驗證。
定期檢查 docker compose logs 有沒有異常登入嘗試。
不需要對外的服務,就不要加 ports:,只走內部網路。
七、結語:從自建服務到數位自主
架設私有雲的過程,其實是一趟重新認識自己資料的旅程。你會開始思考:哪些照片值得留十年?哪些文件真的需要雲端同步?哪些服務其實我根本沒在用?這些問題,在使用商業服務時從來不會浮現,因為一切都被包裝得太過順暢。
2026 年的自建生態已經非常成熟。Docker Compose 把複雜的部署流程簡化成一個 YAML 檔案,社群提供的映像檔品質也越來越好。你不需要成為系統管理員,只需要願意花幾個週末,把這套系統慢慢建起來。
建議的學習路徑是:先從單一服務(例如 Uptime Kuma)開始,熟悉 compose 的寫法與指令。接著加上反向代理,學會用網域與 HTTPS 提供服務。然後陸續補上 Vaultwarden、Nextcloud、Immich。等你跑順了,再來研究自動化備份、監控告警、異地備援。
不要一次全部裝完。自建的樂趣在於慢慢累積,每一個服務都是為了解決你自己的某個真實需求。當你某天打開手機,發現照片自動備份到自己家的硬碟、密碼存在自己的伺服器、影片從自己的媒體庫播放,那種「資料終於回到自己手上」的踏實感,是任何訂閱方案都給不了的。
現在,去把角落那台舊電腦翻出來吧。你的私有雲,從一個 compose.yaml 開始。
```