SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor

Matrix Synapse VPS 自架與長期維護指南

了解在 VPS 長期維持 Matrix Synapse homeserver 所需的配置,包含 1 vCPU、2 GB RAM 的限制、Postgres、media store 清理、註冊防護與雙重備份。

維持 Matrix Synapse homeserver 運作所需的工作

Matrix Synapse 容易安裝,也容易被忽略。安裝只需要加入一個 apt repository、建立一個設定檔、設定一個 reverse proxy 區塊,以及建立一筆 DNS 記錄。讓 homeserver 穩定運作一年則是另一回事:需要使用正式的資料庫、定期清理 media store、限制陌生人註冊,並建立同時涵蓋伺服器兩個部分的備份。

本指南以 Ubuntu 24.04 LTS 為目標,並從 matrix.org apt repository 安裝 Synapse。這是 Synapse 專案為 Debian 和 Ubuntu 維護的套件來源。套件版本每隔幾週就會變更,因此本文不列出版本號。以下所有路徑與選項均來自目前的 Synapse 文件。

Sizing:1 vCPU 和 2 GB RAM 實際能支援什麼

截至 August 2026,已發布的 sizing 頁面通常建議 Synapse homeserver 使用 1 vCPU 和 2 GB RAM。這個建議只適用於一種情況:私人伺服器、少數使用者、小型聊天室,且沒有繁忙的公開聊天室。Synapse 文件也明確說明另一種情況:如果要加入大型公開聊天室,例如 #matrix:matrix.org,「至少需要 1GB 的可用 RAM」。這裡的可用 RAM 是在 Python、Postgres 和 kernel 之外額外需要的記憶體。

加入聊天室的運作方式可能改變 sizing,單一聊天室就足以造成影響。當本機使用者加入聊天室時,homeserver 會成為該聊天室的完整參與者。它會從聊天室中的其他伺服器接收每個事件、驗證每個事件的簽章,並在本機儲存聊天室狀態。大型公開聊天室有數千名成員,分布在數百台伺服器上,因此即使使用者之後不再開啟該聊天室,伺服器仍會持續處理這些工作。之後離開聊天室,也不會刪除已儲存的歷史記錄。

Synapse 的大部分 RAM 用於快取。caches section 包含一個 global_factor,可同時調整所有快取,而 SYNAPSE_CACHE_FACTOR environment variable 會設定相同的值。提高該值會使用更多 RAM,以避免執行資料庫查詢。降低該值則會增加 CPU 和 Postgres 的負載,以節省 RAM。Postgres 也需要自己的記憶體,因此在 2 GB 的伺服器上,兩者會爭用相同的記憶體容量。

對小型方案而言,有兩項實用規則。加入 swap:swap 不會讓 Synapse 變快,但可避免 kernel 在大型加入作業期間終止該程序。接著從第一週開始監控磁碟,因為會無限制增長的兩項內容是 media store 和 room state tables,而且兩者都儲存在磁碟上。

為什麼選擇 Postgres,以及 SQLite 為何不再適用

Debian 套件會從 SQLite 開始使用。這對第一次啟動而言沒有問題,但不適合供其他人使用的伺服器。SQLite 同一時間只允許一個寫入者。聯邦流量與用戶端請求可能同時寫入,因此速度較慢的請求會阻塞其他低成本請求。使用者回報的症狀通常是應用程式偶爾停頓幾秒。

第二個原因是架構限制。Synapse 的 worker processes 是使用多個 CPU 核心的支援方式,而 workers 需要 Postgres。繼續使用 SQLite 不僅會犧牲效能,也會失去後續擴充的升級路徑。

之後再遷移仍受支援,但會造成停機,因此應在有使用者之前完成。Synapse 隨附 synapse_port_db,可將 SQLite 資料庫複製到已準備好的 Postgres 資料庫:

synapse_port_db --sqlite-database homeserver.db --postgres-config homeserver-postgres.yaml

如果您想在 Synapse 旁的容器中執行資料庫,請參閱在 Docker 或主機上執行資料庫,瞭解其中的取捨。

在 Ubuntu 24.04 上安裝 Synapse

sudo apt install -y lsb-release wget apt-transport-https
sudo wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/matrix-org.list
sudo apt update
sudo apt install matrix-synapse-py3

在 Ubuntu 24.04 上,lsb_release -cs會輸出noble,而 matrix.org repository 提供noble套件。請勿使用 Ubuntu 自有 archive 中的matrix-synapse套件。Synapse project 不建議使用該套件,因為這些 build 落後於其 releases,且包含已知的 security bugs。

installer 會要求輸入 server name,並將答案寫入/etc/matrix-synapse/conf.d/server_name.yaml。請仔細輸入。server_name是每個 user ID(@alice:example.com)中冒號後面的部分,也會嵌入 server 建立的每個 room。之後變更此值不會搬移任何內容,而是建立不同的 homeserver。請使用不含主機名稱的網域example.com,即使 Synapse 本身會在matrix.example.com上執行。delegation 會連結兩者,下一節將說明這項設定。

套件會以matrix-synapse使用者執行 Synapse,將資料放在/var/lib/matrix-synapse下,並讀取/etc/matrix-synapse/homeserver.yaml,接著讀取/etc/matrix-synapse/conf.d/中的每個檔案。請將自訂設定放在conf.d中的小型檔案裡。套件升級不會修改這些檔案。

sudo systemctl restart matrix-synapse
systemctl status matrix-synapse
sudo journalctl -u matrix-synapse -n 100 --no-pager

正常啟動時,監聽器會先啟動,之後不再輸出訊息。systemd unit 會在服務結束數秒後重新啟動,因此 Synapse 拒絕的設定會讓 unit 持續啟動後立即結束。journal 的最後幾行會指出它拒絕的 key。

將 Synapse 指向 Postgres

sudo apt install -y postgresql
sudo -u postgres createuser --pwprompt synapse_user
sudo -u postgres createdb --encoding=UTF8 --locale=C --template=template0 --owner=synapse_user synapse

locale 並非僅供顯示。除非在資料庫設定中設定 allow_unsafe_locale,否則 Synapse 無法使用以不同 COLLATECTYPE 值建立的資料庫啟動。之後的文件化修復方式,是將資料庫傾印後重新載入至正確建立的資料庫。請在第一次建立時就設定正確。

database:
  name: psycopg2
  txn_limit: 10000
  args:
    user: synapse_user
    password: secretpassword
    dbname: synapse
    host: localhost
    port: 5432
    cp_min: 5
    cp_max: 10

所有設定檔中只能保留一個 database: 金鑰。請取代 homeserver.yaml 內的 SQLite 區塊,不要在 conf.d 下方再加入第二份設定。如此便不會有設定檔實際採用哪一份的疑問。重新啟動後,確認 Synapse 確實使用 Postgres:

sudo -u postgres psql synapse -c "SELECT count(*) FROM users;"

若輸出數字,表示 Synapse 已在此資料庫中建立結構。若出現找不到 relation 的錯誤,表示它仍在寫入 SQLite 檔案,因此你編輯的設定檔不是實際讀取的檔案。

反向代理、TLS 與 federation 所需的 .well-known 檔案

Synapse 以純 HTTP 監聽 8008 埠,並繫結至 localhost。TLS 與公開連接埠應由前端的反向代理處理。

listeners:
- port: 8008
  tls: false
  type: http
  x_forwarded: true
  bind_addresses:
  - '::1'
  - '127.0.0.1'
  resources:
  - names:
    - client
    - federation
    compress: false

x_forwarded: true 會告知 Synapse 信任代理所設定的 X-Forwarded-For 標頭。若未設定,所有用戶端看起來都來自 127.0.0.1。如此一來,速率限制會將所有請求視為來自同一個極度繁忙的本機使用者,並一併限制所有人。

location ~ ^(/_matrix|/_synapse/client) {
    proxy_pass http://localhost:8008;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host:$server_port;
    client_max_body_size 50M;
    proxy_http_version 1.1;
}

Synapse 文件針對這個區塊有一項警告,許多人因此浪費數天排查問題。不要在 proxy_pass 的埠號後加入路徑,即使只是單一個 / 也不行。nginx 接著會將 URI 正規化,導致傳送端簽署的位元組內容改變。federation 請求會因此無法通過簽章驗證,但一般用戶端請求仍可正常運作。

client_max_body_size 必須至少與 Synapse 的 max_upload_size 一樣大。若 nginx 設定的值較小,超過該限制的上傳會先由 nginx 以 413 Request Entity Too Large 拒絕,Synapse 根本不會收到請求,因此 Synapse 日誌中不會留下可用來說明問題的訊息。

憑證本身請參閱 在 Ubuntu 24.04 上使用 Certbot 與 Let's Encrypt。若尚未決定使用哪個代理,反向代理比較會說明由哪個代理負責 TLS。

委派機制可讓 server_name 維持 example.com,同時讓 Synapse 執行於 matrix.example.com。請從裸網域提供以下兩個檔案:

location /.well-known/matrix/server {
    default_type application/json;
    return 200 '{"m.server": "matrix.example.com:443"}';
}

location /.well-known/matrix/client {
    default_type application/json;
    add_header Access-Control-Allow-Origin '*';
    return 200 '{"m.homeserver": {"base_url": "https://matrix.example.com"}}';
}

伺服器檔案會告知其他 homeserver federation 流量應傳送至何處。如此 federation 就能使用 443,而非預設的 8448 埠。用戶端檔案會告知 Matrix 用戶端哪個 URL 提供 @alice:example.com。用戶端檔案中的 Access-Control-Allow-Origin 標頭很重要,因為以瀏覽器為基礎的用戶端會跨來源擷取該檔案。若沒有此標頭,瀏覽器會封鎖回應,用戶端也會回報找不到你的 homeserver。

兩個檔案都必須由 example.com 本身透過有效的 TLS 提供。先檢查檔案,再檢查外部網路看到的內容:

curl -s https://example.com/.well-known/matrix/server
curl -s https://matrix.example.com/_matrix/federation/v1/version

第一個指令會回傳你撰寫的 JSON。第二個指令會回傳包含伺服器實作及其版本的 JSON 物件,證明代理能透過 federation 路徑連線至 Synapse。接著,使用 https://federationtester.matrix.org 的 Matrix federation tester 測試該網域。這項工具會遵循實際遠端伺服器所使用的相同路徑。

聯邦或不聯邦:刻意做出決定

聯邦是 Matrix 的核心,也是主要成本來源。啟用聯邦的 homeserver 會接受來自陌生伺服器的連線、接收其事件、快取其媒體,並儲存使用者加入之所有聊天室的狀態。這是威脅模型的決策,不應視為預設設定。

如果使用者需要聯絡其他 homeserver 上的人員,或選擇 Matrix 的原因是可攜式身分,請啟用聯邦。如果伺服器只供單一團隊使用,且所有帳號都屬於你的組織,請勿啟用聯邦。封閉式伺服器儲存的資料較少、接收的資料較少,也不容易成為濫用目標。

若要限制聯邦而非完全停用,Synapse 支援 allow list:

federation_domain_whitelist:
- lon.example.com
- nyc.example.com

文件也建議一併在防火牆封鎖聯邦監聽器,讓不必要的流量在網路層停止,而不是進入 Python 後才處理。若要完全關閉聯邦,請從監聽器 resources 清單中移除 federation,不要發布 /.well-known/matrix/server,並保持 8448 埠關閉。

如果執行 Matrix 的原因是提供私人團隊聊天,而聯邦從未是需求的一部分,請在採用 Synapse 前,將執行成本與其他 自架 Slack 替代方案比較。使用 Docker Compose 執行 Rocket.Chat 可在較小的機器上提供團隊聊天,因為它不必儲存其他組織的聊天室狀態。

媒體儲存區會在不知不覺間填滿磁碟

自家使用者上傳的檔案會永久留在磁碟上。其他 homeserver 上的使用者發布檔案後,只要你的用戶端顯示這些檔案,Synapse 就會立即將其擷取並快取到磁碟上。Synapse 也會為圖片產生縮圖,因此一張照片可能變成數個檔案。預設不會自動刪除任何檔案。

找出儲存位置並測量容量:

grep media_store_path /etc/matrix-synapse/homeserver.yaml
sudo du -sh /var/lib/matrix-synapse/media_store

測量你自己的設定檔輸出的路徑。Debian 套件會將 Synapse 的資料放在 /var/lib/matrix-synapse 下,因此儲存區通常就在該處。接著在 conf.d 中設定保留政策:

media_retention:
  local_media_lifetime: 90d
  remote_media_lifetime: 14d

請仔細閱讀這兩行,因為它們屬於不同類型的設定。remote_media_lifetime 會讓快取過期;刪除的內容仍可從擁有該檔案的伺服器重新擷取。local_media_lifetime 則會在自家使用者上傳的檔案達到指定保存期限後永久刪除。如果團隊在聊天室中分享文件,並預期明年仍能找到這些文件,就會遺失這些檔案。許多伺服器只設定遠端媒體的值。

如要執行一次性清理,管理 API 接受以毫秒表示的 Unix 時間戳記:

BEFORE_TS=$(date -d '30 days ago' +%s%3N)
curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
  "https://matrix.example.com/_synapse/admin/v1/purge_media_cache?before_ts=$BEFORE_TS"

POST /_synapse/admin/v1/purge_media_cache 會丟棄在該時間戳記之前最後存取的遠端媒體快取。POST /_synapse/admin/v1/media/delete?before_ts=<ms> 會依相同規則刪除本機媒體。先執行遠端清理,再次測量容量,因為在啟用聯邦功能的伺服器上,遠端快取通常占較大部分。

兩項設定都會影響同一個磁碟。max_upload_size 限制單一上傳的大小,且必須與 nginx 中的 client_max_body_size 保持一致。url_preview_enabled: true 會讓你的伺服器擷取遠端頁面,讓用戶端顯示連結預覽;這會消耗頻寬,也會儲存你未曾接收的內容之縮圖。

關閉註冊,避免他人發現您的 homeserver

掃描器只需幾天就能找到開放的 homeserver。只要任何人都能建立帳號,您的伺服器就會成為與其聯邦的每個聊天室中的垃圾訊息來源,對方的管理員也會封鎖您的整個網域。這種信譽損害會持續到清理完成之後,因為封鎖清單是人工維護的。

Synapse 預設會關閉註冊。enable_registration 預設為 false,而 registration_requires_token 預設為 false。如果啟用註冊卻未設定驗證步驟,Synapse 也不會啟動,除非您另外設定 enable_registration_without_verification: true。這項拒絕啟動的行為是刻意設計的,因此不要只為了消除啟動錯誤而啟用它。

請手動建立您需要的帳號:

sudo register_new_matrix_user -c /etc/matrix-synapse/homeserver.yaml http://localhost:8008

系統會提示您輸入使用者名稱、密碼,以及是否將該帳號設為伺服器管理員。它會從您透過 -c 傳入的設定檔讀取 registration_shared_secret;如果顯示找不到 shared secret,請將 -c 指向存放該 secret 的檔案。

手動建立帳號無法應付規模需求時,可以改用註冊 token。新使用者必須在註冊時提供 token,而每個 token 都能設定可使用的次數上限:

enable_registration: true
registration_requires_token: true
curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uses_allowed": 1}' \
  https://matrix.example.com/_synapse/admin/v1/registration_tokens/new

在內容中省略 token,Synapse 就會產生 token 並回傳。GET /_synapse/admin/v1/registration_tokens 會列出目前有效的 token。這兩個呼叫都需要伺服器管理員帳號的 access token;您可以使用前面建立的管理員使用者登入以取得該 token。

已在其他系統管理帳號的組織,可以完全略過本機密碼,因為 Synapse 能將登入委派給 OIDC(OpenID Connect)provider,例如 以 Authentik 建立自架 SSO provider。這樣即可在同一處管理人員加入與離開組織的流程。

能實際重建伺服器的備份

Synapse 備份包含 3 個部分,缺少任何一個部分,還原出的伺服器都無法正常使用。

  • Postgres 資料庫,其中儲存所有事件、帳戶與房間。
  • media store 目錄,其中儲存所有上傳的檔案。
  • /etc/matrix-synapse,其中儲存設定與伺服器的 signing key。

最容易被遺漏的是 signing key。這是 homeserver 用來簽署事件的私密金鑰,遠端伺服器會使用相符的公開金鑰驗證事件。執行 grep signing_key_path /etc/matrix-synapse/homeserver.yaml 查看金鑰的位置。遺失金鑰後,還原出的伺服器將無法證明自己就是房間原本認得的那台伺服器。

sudo -u postgres pg_dump --format=custom --file=/var/backups/synapse-$(date +%F).dump synapse
sudo tar czf /var/backups/synapse-etc-$(date +%F).tgz -C /etc matrix-synapse

先傾印資料庫,再複製 media store。媒體檔案只會寫入一次,並以 ID 建立參照,因此在傾印後執行的媒體複製只可能包含額外檔案,不會遺漏檔案。若順序相反,還原後的資料庫可能會指向備份中未擷取的檔案。

將這 3 個部分全部備份到 VPS 之外的位置。使用具有異地快照的 restic 很適合這種架構,因為 media store 是較大的部分,且各次執行之間幾乎不會變動,所以 deduplication 能讓每個 snapshot 保持較小。

接著演練還原流程,因為從未還原過的備份只是假設。建立第 2 台 VPS,安裝相同套件,還原設定,使用相同的 encoding 與 locale 建立資料庫,將傾印檔 pg_restore 到資料庫,還原 media store,然後登入。記錄所需時間。這個數字才是實際的復原時間。

狀態資料表不斷成長時:壓縮

Synapse 會將房間狀態儲存為狀態群組。在聯邦伺服器上,state_groups_state 通常會成為資料庫中最大的物件。變更任何設定前,先進行測量:

sudo -u postgres psql synapse -c "SELECT pg_size_pretty(pg_database_size('synapse'));"
sudo -u postgres psql synapse -c "SELECT pg_size_pretty(pg_total_relation_size('state_groups_state'));"

如果該資料表佔資料庫容量的大部分,專案提供了專用的壓縮工具 rust-synapse-compress-state。它會在不改變任何房間狀態意義的前提下,將狀態群組階層改寫為較少的資料列。此工具以 Rust 建置:

sudo apt install -y build-essential libssl-dev pkg-config git
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
git clone https://github.com/matrix-org/rust-synapse-compress-state.git
cd rust-synapse-compress-state/synapse_auto_compressor
cargo build --release
./target/release/synapse_auto_compressor -p postgresql://synapse_user:secretpassword@localhost/synapse -c 500 -n 100

-c 是每次處理的狀態群組數量,-n 是本次執行要處理的區塊數量。自動壓縮工具會記錄處理進度,因此下次執行時會從上次的位置繼續,這也是它適合排程執行的原因。文件指出,這些變更會在 append-only 資料表上以交易方式套用,因此 Synapse 運作期間也能執行。不論如何,第一次執行前都應先備份資料庫。

這裡有一個 Postgres 細節常讓人誤解。刪除資料列後,空間會歸還 Postgres 重複使用,而不是歸還檔案系統。因此大型壓縮作業完成後,df 可能完全不會變小。VACUUM FULL 才會釋放這些空間,但它會在資料表上取得 exclusive lock,並需要約等同於資料表大小的可用磁碟空間。因此,應將它排入維護時段,而不是臨時執行。

確認伺服器運作正常的檢查項目

systemctl status matrix-synapse
curl -s https://example.com/.well-known/matrix/server
curl -s https://matrix.example.com/_matrix/federation/v1/version
sudo -u postgres psql synapse -c "SELECT pg_size_pretty(pg_database_size('synapse'));"
sudo du -sh /var/lib/matrix-synapse/media_store

運作正常表示服務單元處於 active 狀態且未反覆重新啟動、delegation 檔案回傳您的 m.server 值、federation 版本端點回傳 JSON,並且可將兩個大小數值與上個月的數值比較。大小檢查最容易被跳過,而磁碟問題會在毫無警告的情況下使 Synapse 伺服器停止運作:磁碟區填滿後,Postgres 無法寫入,Synapse 也就無法處理所有需要存取資料庫的請求。

FAQ

Matrix Synapse 伺服器需要多少 RAM?

如果是只有少數使用者、小型聊天室,且沒有大型公開聊天室的私人 homeserver,2 GB 即可運作。這也是截至 August 2026,多數已發布的規模估算頁面所建議的配置。若使用者會加入 #matrix:matrix.org 這類大型公開聊天室,Synapse 文件要求除其他需求外,至少保留 1 GB 可用 RAM,因為伺服器會儲存該聊天室的狀態,並持續處理其網路流量。在 2 GB 方案上加入 swap,避免單次大型加入操作導致 kernel 終止程序。

我一定要使用 PostgreSQL,而不是 SQLite 嗎?

使用者超過少數幾名後,是的。SQLite 同一時間只允許一個寫入者,因此在負載增加時,聯邦流量與用戶端請求會互相阻塞,請求可能一次卡住數秒。Synapse 的 worker process 是使用多個 CPU core 的支援方式,而這需要 Postgres。之後仍可使用 synapse_port_db 進行遷移,但會造成停機,因此請在有使用者之前,先使用 --encoding=UTF8 --locale=C --template=template0 建立資料庫。

為什麼我的 Synapse 磁碟使用量持續增加?

原因通常是其中一個目錄和一個資料表。media store 會保留伺服器所在聊天室中上傳的每個檔案,包括遠端使用者 media 的快取副本與產生的縮圖。除非設定 media_retention,否則這些檔案不會過期。聯邦伺服器上的 state_groups_state 資料表會隨聊天室狀態增加,而 rust-synapse-compress-state 可降低其大小。在決定處理哪一項之前,先使用 du -sh 檢查 media_store_path,並使用 SELECT pg_size_pretty(pg_total_relation_size('state_groups_state')); 檢查另一項。

如何阻止陌生人在我的 homeserver 註冊?

enable_registration 保持為預設值 false,並使用 register_new_matrix_user 建立帳戶。當這種方式無法再擴充時,設定 enable_registration: trueregistration_requires_token: true,再發放透過 POST /_synapse/admin/v1/registration_tokens/new 建立的 token。不要只為了消除 Synapse 啟動時拒絕服務的訊息而設定 enable_registration_without_verification: true,因為開放的 homeserver 會成為 spam 來源,其他管理員也可能因此封鎖你的整個網域。

我的 homeserver 應該啟用聯邦嗎?

聯邦是關於暴露範圍的決策,不是預設功能。如果使用者需要聯絡其他 homeserver 上的人員,才啟用聯邦。如果伺服器只服務單一團隊,請保持停用,因為非聯邦伺服器儲存的資料較少、接收的流量較少,也較不容易受到濫用。在兩者之間,federation_domain_whitelist 可將聯邦限制為指定的合作夥伴網域。Synapse 文件也建議同時在防火牆限制聯邦 listener,而不要只依賴應用程式層的檢查。

#matrix#synapse#self-hosting#postgresql#federation