本篇文章更新時間:2025/04/27
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣 或 新台幣 贊助支持。
這套 Mastodon 的社群媒體工具觀望很久,遲遲沒有下手安裝的原因,就是太複雜了啦!最原始的從原始碼安裝需求,會要 Ruby, PostgreSQL, NodeJS 基本環境之外,還要 Nginx, SSL, WebSocket 等網路環境的搭配,光打這些字都覺得累了!
不過還好,官方的 GitHub Repo 已經有提供方便安裝與啟動的 docker-compose.yml 檔案,也不需要自己 build image 映像檔,可以執行官方已經預先編譯好的映像檔。
以下進入使用 Docker 安裝這服務的輕鬆環節~
內容目錄
前置準備
- 至少要有 Docker 的運作環境
- Nginx 反向代理服務
- 用來識別位置的網域名稱
主機網路架構
畢竟是要做社群媒體站,一台可以上網的主機與公開的網路環境。
本篇我的架構稍微特別一點:
內網主機 (Docker + Nginx) <--- WireGuard ---> 外網主機 (Nginx) <-> Cloudflare (SSL)
內網主機利用 Docker + Nginx 把服務包在 Port 80 上,外網主機純粹做對外曝光的操作,Cloudflare 負責 SSL 憑證的處理與防火牆。
內網主機(Docker + Nginx)
系統是 Ubuntu 24.04 ,先是安裝 Docker:
curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh
Nginx 我不是使用容器來處理,單純就是把這一層獨立安裝。基本上只要能接管主機網路 Port 80 做第一層轉發都可以。
再來開始安裝 Mastodon 環節:
# git clone https://github.com/mastodon/mastodon.git
# cd mastodon
# git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
# cp .env.production.sample .env.production
寫文當前 Docker 版本為
Client: Docker Engine - Community
Version: 28.0.4
API version: 1.48
Go version: go1.23.7
Git commit: b8034c0
Built: Tue Mar 25 15:07:16 2025
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 28.0.4
API version: 1.48 (minimum version 1.24)
Go version: go1.23.7
Git commit: 6430e49
Built: Tue Mar 25 15:07:16 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.27
GitCommit: 05044ec0a9a75232cad458027ca83437aae3f4da
runc:
Version: 1.2.5
GitCommit: v1.2.5-0-g59923ef
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Mastodon 透過 git
指令切換最新版本,當前使用 v4.3.7
。
輸入下方指令啟用組態設定工具
docker compose run --rm web bundle exec rake mastodon:setup
需要準備好 Domain 與 SMTP 資訊(非必要,但做通知方便),過程會問一些問題,像是設定 Domain、設定 PostgreSQL 資料庫連線資訊、Redis 資料庫等,除非有客製化需求,不然問是不是正在使用 Docker 服務安裝的時候,選擇 yes,這些需要連線憑證來使用的服務都用預設方式,一步一步 Enter 即可。
一直到詢問結束前,會輸出一堆設定屬性參數值,並提問是否要儲存到 .env.production
檔案,這裡其實並不會去儲存,所以需要把設定值手動先覆寫 .env.production
檔案(開新視窗操作)。
然後才輸入「Yes」,讀取這個檔案,開始初始化資料庫。
到結束前,會設定 admin 管理員的帳號密碼,要記得最後輸出的密碼!
組態設定檔案範例如下:
WEB_DOMAIN=mxp.tw
LOCAL_DOMAIN=mxp.tw
SINGLE_USER_MODE=true
SECRET_KEY_BASE=SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_
OTP_SECRET=SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_
VAPID_PRIVATE_KEY=SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_-5_ZAM=
VAPID_PUBLIC_KEY=BPeHSFpcac87-SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_-SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_=
DB_HOST=db
DB_PORT=5432
DB_NAME=postgres
DB_USER=postgres
DB_PASS=
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=
SMTP_SERVER=smtp.mailgun.org
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=SECRET_KEY_SECRET_KEY_SECRET_KEY_SECRET_KEY_
SMTP_AUTH_METHOD=plain
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_ENABLE_STARTTLS=auto
SMTP_FROM_ADDRESS=Mastodon
WEB_DOMAIN 的參數預設不會出現,但這是 Mastodon 服務給的彈性,讓你可以「網站用子網域提供服務」但使用者完整 ID 能用「主網域」(感覺比較好看?)
到初始化完成資料庫(./postgres14
)後,會結束組態檔案產生的畫面,接著編輯 docker-compose.yml
檔案,將其中對外阜號的 127.0.0.1:3000:3000
改為 3000:3000
( streaming 的 127.0.0.1:4000
Port 也是照樣改)
上面這段修改如果沒有像我再多一層外網節點的連結其實就不必了。
完成後使用指令: docker compose up -d
初始化啟動服務。
接著要做一件修改權限的操作,我在這邊踩了個大雷,測了好久。因為檔案目錄權限不對,所以導致資料都無法寫入,而變成服務有開起來,但就是在資訊同步上出問題。
修正檔案權限
先取得使用者 ID,再用來修正權限。指令對應容器名稱與 mastodon
使用者,沒意外就是 991
。
# docker exec mastodon-web-1 id -u mastodon
然後 chown 991 -R ./public
把原始檔案目錄下的 public
目錄整個權限調整給容器使用者。
完成後重啟容器: docker compose restart
設定內網主機 Nginx 反向代理功能
現在服務開起來後主要有兩個對外的服務 3000
Port 的 Mastodon 網站服務,還有 4000
Port 的 streaming 服務(WebSocket)。
內網主機的 Nginx 設定如下:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name mxp.tw;
root /path/to/mastodon/public;
location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri @proxy;
}
location /sw.js {
add_header Cache-Control "public, max-age=0";
try_files $uri @proxy;
}
location @proxy {
proxy_set_header Host mxp.tw;
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 https;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://127.0.0.1:3000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
location /api/v1/streaming {
proxy_set_header Host mxp.tw;
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 https;
proxy_set_header Proxy "";
proxy_pass http://127.0.0.1:4000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
location /.well-known/ {
allow all;
try_files $uri @proxy;
}
location / {
try_files $uri @proxy;
}
}
主要注意 proxy
的設定中 X-Forwarded-Proto
要是 https
所以儘管我用 80 的 HTTP 來傳輸,但還是要讓容器內的服務以為正在使用加密連線,避免無限重導向發生。
到這步,已經將整個 Mastodon 服務包裝好在內網主機,如果此時有其他區網主機要測試就已經可以正式使用。
接下來就是將此服務對外網開放。
外網主機(Nginx)
基本上到這步已經很簡單了,只需要將外部的請求轉發給內網主機的 Nginx 服務。
設定如下:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name mxp.tw;
location /api/v1/streaming {
proxy_set_header Host mxp.tw;
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 https;
proxy_set_header Proxy "";
proxy_pass http://10.10.10.2:4000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
location / {
proxy_set_header Host mxp.tw;
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 https;
proxy_pass_header Server;
proxy_pass http://10.10.10.2:80;
}
}
這邊要注意的有兩點,Host 要對應到內網 Nginx 設定的網域,所有的請求都轉發給內網主機的 80 Port,但是 WebSocket 的請求要特別對應內網主機的 4000 Port。
Cloudflare (SSL)
這步驟使用 Cloudflare 主要兩個點:
- SSL 憑證我直接用他家的,省的處理 Let's Encrypt。
- 畢竟是社群媒體服務,前面還是掛一個 CDN+WAF 服務保險,還免費的,不香嗎!
不過要注意不要讓防火牆把關鍵的 WebFinger 服務給擋下來了。
備份與還原 Mastodon 資料
其實整個服務的設計與安裝都算是巧妙,到目前為止以及這樣正式營運一個社群媒體服務,資料通通都在當初 git clone
下來的 mastodon
目錄裡。
簡單來說,把整個目錄打包起來,就是從原始碼到使用者資料都一起了。
有網友分享的 Shell Script 如下:
set -e
NOW=$(date +%F)
# backup postgres
docker exec -it mastodon-db sh -c "pg_dumpall -U postgres > /tmp/all.sql"
docker exec -it mastodon-db sh -c "cp /tmp/all.sql /postgres_backups/all.sql"
# pack everything of value into zip
zip -r ./backup_$NOW.zip ./redis ./postgres_backups ./public ./backup.sh ./docker-compose.yml ./.env.production ./proxy -x "public/system/cache/**"
Ref: GitHub - shukriadams/mastodon-docker-simple-setup
還原則是把匯出的資料庫檔案重新匯入回去:
docker exec -it mastodon-db psql -U postgres --set ON_ERROR_STOP=off -f /postgres_backups/all.sql
用容器開服務真的是方便R~
更新 Mastodon 版本
因為是用 Git 直接從原始碼的 Repo 抓下來,所以也不難:
git fetch
指令將 repo 程式碼更新- 輸入
git status
確認有動到的設定(可能是docker-compose.yml
檔案) - 有改動的話,先用
git stash
指令把修改的暫存起來。 - 使用
git checkout v版本號
前,確認是使用前面提到的git stash
還是git commit
,如果是stash
切換到最新版後使用git stash pop
還原修改套用當前版本,如果是commit
的話就要改用merge
指令了。總而言之就是切換版本並保留原本客製化調整的部分。 - 由於有更新版本,官方提供的
docker-compose.yml
也會有變動版本,如果不是自己 build 映像檔的話,就是先docker-compose pull
,如果是自己有做調整,那就是需要重新docker-compose build
過。 - 準備好映像檔 image 後,就是關停當前的容器,
docker compose down
,然後重新啟動docker compose up -d
。如果是使用官方 build 好的版本,直接關停後重啟也會自己 pull 過。 - (選擇性操作)使用
docker compose run --rm web rake db:migrate
確保有無資料庫的升級。 - (選擇性操作)使用
docker compose run --rm web rake assets:precompile
重新編譯過靜態相關文件。
Ref: McKael/mastodon-documentation/blob/master/Running-Mastodon/Docker-Guide.md
後記
其實看下來主體就是那包原始碼與容器映像檔的服務。其他都是網路服務的配置而已。
看起來 ActivityPub 協議 用在串聯彼此又不會失去內容與注意力主權,真的很棒啊~
「在 Meta 的辯護聲明中,他們展示了一張圖表,顯示用戶觀看「朋友」所發內容的比例,在 Facebook 上從 22% 降至 17%,在 Instagram 上則從 11% 降至 7%。」
比起過時又長篇大論的 RSS Feed,那換一個輕鬆交流的方式吧!
WordPress 也有社群維護的 ActivityPub 外掛可以使用,讓你的網站也能在發佈內容後從像是 Mastodon 的服務來接收通知。
- 驗證社群個人資訊頁面的工具: mastodon-link-debugger - 檢查分享出去對應的網站與個人資訊卡的設定是否正確。
- 台灣 Mastodon 的相關資源: awesome-fediverse-in-taiwan - 要找到台灣同好,以及 Mastodon 中繼站可以到這邊看看~