先知道:Zeabur 有內建備份,但不一定夠用
依 Zeabur 文件,資料庫服務的「備份」分頁按下「備份」,等幾分鐘就能下載。這個功能限付費方案,備份保留 7 天後自動刪除。
| 資料庫 | Zeabur 內建備份的格式 | 用什麼還原 |
|---|---|---|
| PostgreSQL | pg_dumpall 產生的 .sql,包含服務裡所有資料庫 | psql |
| MySQL / MariaDB | .sql,包含所有非系統資料庫 | mysql |
| MongoDB | 多個 .bson 檔 | mongorestore |
我們的建議:內建備份下載一份,再用下面的指令自己備一份。 原因在 PostgreSQL 那段:要搬到代管型資料庫時,內建備份的格式會出錯。
連線資訊在哪
依 Zeabur 的 PostgreSQL 模板說明,資料庫服務的 Instruction 分頁裡,Public (External) 區塊有對外用的 Connection String 和連線指令。主機名稱長得像 hkg1.clusters.zeabur.com,連線埠是 Zeabur 分配的號碼。
結尾是 zeabur.internal 的主機名稱只能在 Zeabur 內部使用,從你的電腦連不到。
下面的指令都用 Docker 執行,本機不需要安裝資料庫工具。
PostgreSQL
1. 先確認伺服器版本
docker run --rm postgres:17 psql "postgresql://USER:PASS@HOST:PORT/DB" -tAc "show server_version"
pg_dump 的版本必須大於或等於伺服器版本。 我們用 15 版的 pg_dump 備份 16 版的伺服器,會直接中止:
pg_dump: error: aborting because of server version mismatch
pg_dump: detail: server version: 16.15 ...; pg_dump version: 15.19 ...
所以下面的映像版本(postgres:16)要換成和你伺服器相同或更新的大版本。
2. 備份(推薦用 custom 格式)
docker run --rm -v "$PWD:/out" postgres:16 \
pg_dump "postgresql://USER:PASS@HOST:PORT/DB" -Fc -f /out/backup.dump
3. 還原到 Neon、Supabase 這類代管資料庫
代管資料庫給你的帳號不是 superuser,而 Zeabur 上資料表的擁有者是 root。直接還原會出現:
pg_restore: error: could not execute query: ERROR: role "root" does not exist
加上 --no-owner --no-acl 就能避開,實測零錯誤,資料筆數正確,新插入的 id 也正確接續原本的序列:
docker run --rm -v "$PWD:/out" postgres:17 \
pg_restore --no-owner --no-acl -d "新資料庫的連線字串" /out/backup.dump
用 Zeabur 內建備份的 data.sql 還原
Zeabur 文件的做法是解壓縮後執行:
psql -h 主機 -p 連線埠 -U 使用者 postgres < data.sql
我們用同樣格式(pg_dumpall)實測的結果:
- 還原到自己管理的 PostgreSQL(有 superuser):成功,資料完整
- 還原到代管資料庫(非 superuser):失敗,出現
ERROR: permission denied to alter role。這種情況請改用上面的pg_dump -Fc
資安提醒:
data.sql開頭有這兩行:
CREATE ROLE root;ALTER ROLE root WITH SUPERUSER ... PASSWORD 'SCRAM-SHA-256$...';也就是說,還原後資料庫密碼會變回 Zeabur 上的舊密碼。Zeabur 發生過資安事件,還原完請立刻改密碼:
ALTER ROLE root WITH PASSWORD '新的長密碼';Zeabur 文件也提到,如果想保留目前的密碼,可以在還原前先刪掉
data.sql裡的CREATE ROLE和ALTER ROLE兩行。
驗證備份(5 分鐘,強烈建議)
在本機開一個空的資料庫,把備份還原進去,確認資料表與筆數正確:
docker network create restore-net
docker run -d --name restore-test --network restore-net -e POSTGRES_PASSWORD=x postgres:17
# 等幾秒讓資料庫啟動完成
docker run --rm --network restore-net -v "$PWD:/out" postgres:17 \
pg_restore --no-owner --no-acl -d "postgresql://postgres:x@restore-test:5432/postgres" /out/backup.dump
docker exec restore-test psql -U postgres -tAc "select count(*) from 你的資料表"
# 確認完就清掉
docker rm -f restore-test && docker network rm restore-net
為什麼不用
-p 5433:5432開 port? 我們第一次測試就是這樣寫的,結果測試機的 5433 port 上剛好有另一個本機 PostgreSQL,備份就被還原進了那台資料庫。改用 Docker 網路,測試資料庫完全不對外開 port,就不會連錯資料庫。
MySQL / MariaDB
# 備份:--single-transaction 不鎖表;--routines --triggers 連預存程序與觸發器一起備份
docker run --rm -v "$PWD:/out" mysql:8 sh -c \
'mysqldump -h HOST -P PORT -u USER -pPASS --single-transaction --routines --triggers DB > /out/backup.sql'
# 還原
docker run --rm -v "$PWD:/out" mysql:8 sh -c 'mysql -h 新HOST -P 新PORT -u USER -pPASS DB < /out/backup.sql'
實測:資料、1 個預存程序、1 個觸發器都完整搬過去。
MongoDB
docker run --rm -v "$PWD:/out" mongo:7 \
mongodump --uri "mongodb://USER:PASS@HOST:PORT/?authSource=admin" --archive=/out/backup.archive --gzip
docker run --rm -v "$PWD:/out" mongo:7 \
mongorestore --uri "新的連線字串" --archive=/out/backup.archive --gzip
實測輸出:50 document(s) restored successfully. 0 document(s) failed to restore.
Redis
大多數人只拿 Redis 當快取,這種情況不用搬,新的 Redis 跑起來會自己重建快取。如果你真的在 Redis 裡存資料(例如佇列、排行榜):
docker run --rm -v "$PWD:/out" redis:7 redis-cli -h HOST -p PORT -a PASS --rdb /out/dump.rdb
成功時會顯示 Transfer finished with success。把 dump.rdb 放進新 Redis 的資料夾(官方映像是 /data)再啟動,就會自動載入。實測 key 數量一致。
還原後必做
- 換上新的連線字串(
DATABASE_URL之類),並換掉資料庫密碼 - 挑幾張重要的資料表,比對筆數
- 新平台開啟每日自動備份,並且實際下載一次,確認拿得到