•
使用 Fedora CoreOS 在雲端部署 Misskey 聯邦宇宙節點
20 分鐘閱讀 •
這篇文章要分享的是我架設 Misskey 伺服器的經驗。我選擇了一條跟大多數人不太一樣的路:用 Fedora CoreOS 搭配 Ignition 設定檔來部署,而不是常見的 Docker Compose 加上 Ubuntu。
為什麼要這麼做?那是因為我想實現一個理想:透過設定檔一鍵重建整台伺服器。
從搬家說起
2022 年,我加入了 liker.social 這個 Mastodon 伺服器,開始了我的聯邦宇宙之旅。這幾年來,我在上面認識了不少有趣的人,也累積了一些追隨者。然而,liker.social 將在 2026 年 1 月 26 日關站。
我很感謝 liker.social 陪伴的這段時光。同時,我也面臨抉擇:我要搬去哪裡?
於是我開始以建置維運的角度研究各種聯邦宇宙的實作。
最知名的 Mastodon;
網友們針對單人實例需求推薦的 GoToSocial;
研究了極輕量的 Hollo;
但最後我被 Misskey 的特色吸引了。
什麼是 Misskey?
Misskey 是一個來自日本的開源去中心化社交平台,實作了 ActivityPub 協定,可以和 Mastodon、Pleroma 等其他聯邦宇宙平台互通。
它有幾個讓我特別喜歡的特點:
介面精美。Misskey 的 Web 介面設計感很強,支援多欄佈局、佈景主題自訂,暗黑模式當然也沒問題。整體視覺體驗比 Mastodon 更活潑。
功能豐富。除了基本的發文、轉發、追蹤,Misskey 還有頻道、天線(自訂過濾時間軸)、雲端硬碟(管理上傳檔案)、自訂表情符號、MFM(專屬的標記語言,可以讓文字動起來)等功能。
可玩性高。對於喜歡折騰的人來說,Misskey 有很多可以自訂的地方:角色系統、徽章、小工具、外掛,甚至還有成就系統。這些小設計讓經營伺服器變得有趣。
技術架構現代。後端用 Node.js,資料庫用 PostgreSQL,搜尋引擎支援 Meilisearch。官方提供了 Docker Compose 安裝指南,部署起來不會太困難。
在讀過完整文件之後,我確信 Misskey 可以配合我設計的這一套 Infrastructure as Code 流程。得益於聯邦宇宙的可遷移設計,我可以把追隨者從舊家無痛轉移過來。
從一個痛點說起
主機掛了要重建、想在另一台機器測試,才發現就連怎麼設定 OS、設定這些容器、怎麼建置備份還原系統都是一堆手動步驟。
文件可以寫,但文件會過時,而且人會偷懶 😅。我想要的是一種方式,讓 設定檔本身就是文件,而且整台伺服器就是照著它跑起來的。
這就是「Infrastructure as Code」的核心理念。而 Fedora CoreOS 的設計剛好完美契合這個需求。
為什麼選擇 Fedora CoreOS?
Fedora CoreOS (FCOS) 是 為容器工作負載設計的精簡原子化作業系統。它有幾個特性讓我非常喜歡:
第一,它的 根檔案系統是唯讀的。這聽起來很麻煩,但其實是個優點:你不能手動 SSH 進去亂改東西,所有變更都必須透過正式的設定流程。這讓系統狀態變得可預測、可重現。
第二,它有 自動更新機制。系統會在背景下載安全更新,重新開機後切換到新版本。如果更新出問題,還能自動回滾。身為一個不想天天盯著伺服器的人,這功能太棒了。
第三,它是 原子化系統。系統更新是以整個映像檔的方式進行,而不是單一套件。你用的系統和其它使用者一致。這讓系統更可靠且不容易出錯。
最後也是最關鍵的,它使用 Ignition 做初始化。
既 Fedora Kinoite 之後我又多了一個沒人在用的系統 😂
附上這張同事傳給我的圖
Butane:讓設定檔變得人類可讀
Ignition 設定檔是 JSON 格式,機器讀得很快,但人類寫起來會抓狂。官方提供了 Butane 這個工具,讓我們可以用 YAML 格式寫設定,再轉譯成 JSON。
podman run --interactive --rm --security-opt label=disable \
--volume "${PWD}":/pwd --workdir /pwd \
quay.io/coreos/butane:release --pretty --strict \
misskey-fcos.bu > misskey-fcos.ign
.bu 檔案是人類寫的 YAML,.ign 檔案是給 FCOS 讀的 JSON。轉譯過程中 Butane 還會幫你檢查語法錯誤,算是多一層保障。
有了這個理解,接下來我要帶你看我怎麼設計這份設定檔。
第一步:選擇主機
我選擇 DigitalOcean 來託管。它是老牌的雲端主機商,口碑不錯,亞洲區有新加坡機房,對台灣連線速度佳。透過上面的推廣連結註冊你可以拿到 60 天內 200 美元試用額度,足夠把各種功能玩透。DigitalOcean 的註冊優惠都是這個價,用我的推廣就當成是對我小額贊助吧!😉
規格方面,我建議選擇 CP 值最高的 每月 6 美元的方案 (1GB RAM / 1 vCPU)。4 美元的方案記憶體只有 512MB,無法執行 Misskey。
DigitalOcean 的 Volume 是每 GB 每月 0.10 美元。我掛一個 8GB 的 Volume 當 Swap,每月只要 0.80 美元。相較之下,升級到 2GB RAM 的方案要 每月 12 美元,價差超過 10 倍。
在 Butane 設定檔中,我讓系統開機時自動把這顆 Volume 格式化成 swap 並掛載:
storage:
disks:
- device: /dev/disk/by-path/pci-0000:00:05.0-scsi-0:0:0:1
wipe_table: true
partitions:
- number: 1
label: swap
size_mib: 0 # 整顆磁碟都給 swap
filesystems:
- device: /dev/disk/by-partlabel/swap
format: swap
wipe_filesystem: true
with_mount_unit: true
with_mount_unit: true 會讓 Butane 自動產生 systemd mount unit,開機就會掛載。
第二步:安全性設計
部署在公網上的伺服器,安全性是第一優先。我的設定有幾個重點:
SSH 只允許金鑰認證。設定檔裡會寫入我的公鑰,並且停用密碼登入:
passwd:
users:
- name: core
ssh_authorized_keys:
- "ssh-ed25519 AAAA... your-key-here"
groups: [wheel, sudo]
storage:
files:
- path: /etc/ssh/sshd_config.d/20-disable-passwords.conf
contents:
inline: |
PasswordAuthentication no
SSH Port 改成非標準的 22222。這不是真正的安全措施,但能大幅減少自動化掃描和暴力破解嘗試:
- path: /etc/ssh/sshd_config.d/10-custom-port.conf
contents:
inline: |
Port 22222
另外,因為 FCOS 預設啟用 SELinux,改了 SSH Port 之後要告訴 SELinux 這是合法的。設定檔裡有一個 systemd service 會處理這件事:
- name: selinux-ssh-port.service
enabled: true
contents: |
[Service]
Type=oneshot
ExecStart=/usr/sbin/semanage port -a -t ssh_port_t -p tcp 22222
當然也不要忘了,在 DigitalOcean 控制台的防火牆設定裡開放這個 Port。我在系統進入穩定,不需要常常連線時也會手動關閉這條防火牆規則,下次要連線時再打開。
第三步:容器架構設計
Misskey 需要以下幾個服務一起運作:
- Misskey 本身(Node.js 應用程式)
- PostgreSQL 資料庫
- Redis 快取
- Meilisearch 全文搜尋(可選但推薦)
- Traefik 反向代理(處理 SSL 和路由)
傳統做法是用 Docker Compose 把這些服務編排起來。但在 FCOS 上,我選擇用 Podman Quadlet。
這帶來幾個好處:容器變成 systemd 服務,可以用 systemctl 指令管理;可以設定服務之間的相依性(比如 Misskey 要等 PostgreSQL 起來才啟動);系統重開機後服務會自動恢復。
更重要的是,所有容器都以 rootless 模式 執行。它們跑在普通使用者 core 的權限下,大幅降低被攻破後的風險。
Quadlet 檔案放在 /var/home/core/.config/containers/systemd/ 目錄下。以 PostgreSQL 為例:
[Container]
ContainerName=db
Image=docker.io/postgres:18-alpine
Network=misskey.network
EnvironmentFile=/var/misskey/config/docker.env
Volume=/var/misskey/db:/var/lib/postgresql:Z
HealthCmd=pg_isready -U misskey -d misskey
HealthInterval=5s
HealthRetries=20
:Z 是 SELinux 的 context 設定,讓 Podman 自動處理權限問題。HealthCmd 則是健康檢查,systemd 會根據這個判斷服務是否正常。
所有容器共用一個內部網路 misskey.network,讓它們可以透過容器名稱互相溝通。Misskey 的設定檔裡寫 host: db 就能連到 PostgreSQL,不需要知道實際 IP,而 db 也不會暴露在外網。
第四步:SSL 憑證自動化
網站要上 HTTPS,需要 SSL 憑證。我用 Traefik 當反向代理,它能自動向 Let's Encrypt 申請憑證。
- path: /etc/sysctl.d/99-unprivileged-ports.conf
contents:
inline: |
net.ipv4.ip_unprivileged_port_start=0
這樣 Traefik 就能以 rootless 模式監聽 443 port 了。
至於 SSL 憑證的申請,我使用 DNS Challenge 而不是 HTTP Challenge。DNS Challenge 的原理是在你的 DNS 記錄裡加一條 TXT 記錄來證明你擁有這個網域,不需要開 Port 80,而且支援萬用字元憑證。
我的網域放在 Cloudflare,Traefik 內建支援 Cloudflare 的 API,設定起來很簡單:
certificatesResolvers:
cloudflare:
acme:
email: your-email@example.com
storage: /acme/acme.json
dnsChallenge:
provider: cloudflare
只需要提供 Cloudflare 的 API Token(有 Zone:Read 和 DNS:Edit 權限),Traefik 就會自動處理憑證申請和續約。
第五步:備份與災難復原
這是整個設計中我最得意的部分 😤
我用 Restic 把 PostgreSQL 資料庫備份到 Cloudflare R2(S3 相容的物件儲存)。R2 提供 每月 10GB 免費空間,小型伺服器綽綽有餘。
備份腳本的設計按照最佳實踐使用 pg_dumpall 串流輸出,並直接 pipe 給 Restic。
podman exec db pg_dumpall -U misskey | \
podman run --rm -i \
--env-file /var/misskey/backup/restic.env \
docker.io/restic/restic:latest \
backup --stdin --stdin-filename "misskey-db.sql"
systemd timer 會每天自動執行,並且套用保留策略,舊的備份會自動清除。
資料庫還原後還有個問題:Meilisearch 的搜尋索引不會自動重建。這代表還原前發布的文章會消失在搜尋結果中。
為了解決這個問題,我寫了 rebuild-meilisearch-index.sh 腳本。它會在資料庫還原後、Misskey 啟動前執行一次,自動從 PostgreSQL 提取所有文章並重建 Meilisearch 索引。
這代表什麼?代表 災難復原變成一鍵部署。
假設哪天主機掛了,我只需要:
- 直接砍了舊主機。沒錯,刪除 VM!
- 用同一份 Ignition 設定檔開一台新的 VM
- 把 DNS 指向新 IP
- 完成
系統初始化時會自動從 S3 拉取最新備份並還原,幾分鐘後服務就上線了。
VM 再也不是寵物,而是牲畜。
需要準備什麼?
整理一下,在使用這份設定檔之前,你需要先準備:
DigitalOcean 相關:帳號、SSH 金鑰、上傳 FCOS 映像檔(從 Fedora CoreOS 下載頁面 取得 DigitalOcean 版本,參考 官方 DigitalOcean 部署文件)
Cloudflare 相關:帳號、網域、API Token(需要 Zone:Read 和 DNS:Edit 權限)
Cloudflare R2:建立兩個 bucket,一個給備份用,一個給 Misskey 的媒體檔案用
各種密碼和金鑰(以 openssl rand -base64 32 產生):PostgreSQL 密碼、Meilisearch Master Key、Restic 備份密碼
部署流程
下載我的 Butane 模板,填入所有
<PLACEHOLDER>標記的值用 Butane 轉譯成 Ignition 設定檔
podman run --interactive --rm --security-opt label=disable \ --volume "${PWD}":/pwd --workdir /pwd \ quay.io/coreos/butane:release --pretty --strict \ misskey-fcos-template.bu > misskey-fcos.ign在 DigitalOcean 建立 Droplet,選擇你上傳的 FCOS 映像檔,新增 Volume,在 User Data 貼上 Ignition 設定檔
等待五分鐘 ☕ (系統會重開機幾次來安裝套件)
SSH 連入檢查狀態,記得要把 DigitalOcean 的防火牆規則設定打通!
ssh -p 22222 core@your-server-ip systemctl --user status misskey-web
這種做法適合誰?
老實說,用 Fedora CoreOS 部署 Misskey 的難度比一般方式高了不少。你需要先搞懂 Ignition、Butane、Podman Quadlet 這些工具,還要習慣「不要 SSH 進去手動改東改西」的維護理念。
但如果你跟我一樣 是個怪咖 ,受夠了「這台伺服器到底改過什麼」的困擾,想要一份能完整描述系統狀態的設定檔,那這種玩法包你滿意。
一份 YAML 檔案定義整台伺服器。想重建?轉譯、部署、等五分鐘。資料庫自動從雲端還原,SSL 憑證自動申請,服務自動啟動。
這就是我追求的 Infrastructure as Code。

延伸閱讀
- Fedora CoreOS 官方文件
- Ignition 官方文件
- Misskey Hub 繁體中文
- Misskey Docker 安裝指南
- Misskey Docker Compose 範例檔案
- 在 DigitalOcean 部署 Fedora CoreOS



回覆
你可以使用 Misskey 或其他 ActivityPub/Fediverse 帳號來公開回覆此文章。現有的公開回覆顯示在下方。