SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-10-28

如何在 VPS 上部署 Paperless-ngx 文件管理系統

透過 Docker Compose 在 VPS 部署 Paperless-ngx。本指南涵蓋 PostgreSQL 設定、PAPERLESS_URL 變數配置、OCR 語言優化、HTTPS 反向代理及自動化備份策略,助您建立可搜尋的數位文件庫。

您要建置的內容

在 VPS 上執行 Paperless-ngx,可以將掃描紙本的資料夾轉成可搜尋的檔案庫。您只要將 PDF 放入受監控的目錄,伺服器就會執行 OCR(光學字元辨識)、擷取文字、推測日期與對應者,然後完成歸檔。安裝只需要一個 Docker Compose 檔案,其中包含 4 個服務。之後的工作都是設定,而本指南大部分篇幅也都用於此處,因為安裝最容易在設定階段失敗。它不是相片庫:OCR 與對應者推測功能不適用於存放旅遊 JPEG 的資料夾,因此請將這類檔案交給專為相片打造的伺服器,讓 Paperless 專心處理紙本文件。影片也是同樣的情況:翻錄電影的收藏應放在媒體伺服器上,透過類似以 90 年代出租店風格打造的 Jellyfin 前端瀏覽內容,而不是將搜尋作為主要用途。

Paperless-ngx 是原始 Paperless 專案的社群維護分支。它免費、可自行代管,並以一般檔案形式將文件儲存在磁碟上,因此您不會失去對自己檔案庫的存取權。在 VPS 上執行,而不是使用家用電腦,表示您可以從任何地方存取掃描檔案,無須在家用路由器上開放連接埠;它也很適合搭配用於非紙本檔案的私有 Nextcloud 執行個體。同樣的原則也適用於連接掃描器的桌上型電腦,因為在該 VPS 上自行執行RustDesk relay,就能從其他地方操作那台電腦,同樣不必在路由器上開啟連接埠。

實際執行的堆疊

官方 compose 檔案會啟動 4 個容器。了解各容器的用途後,較容易讀懂日誌。

  • webserver:paperless-ngx 本身的映像檔。它提供 Web 介面與 API,監看輸入資料夾的 consumer,以及負責 OCR 的 Celery 工作程序。
  • db:PostgreSQL。它儲存中繼資料、標籤、往來對象及全文搜尋索引資料表。不會儲存您的 PDF。
  • broker:Valkey,相容於 Redis 的鍵值儲存區。它是 Web 程序與工作程序之間的工作佇列。
  • gotenberg 與 tika:選用元件,只有在 -tika compose 變體中使用。它們會將 Office 文件(.docx、.xlsx、.odt)轉換為 PDF,讓 paperless 能夠建立索引。

截至 October 2026,postgres compose 檔案會固定使用 docker.io/library/postgres:18 與 docker.io/valkey/valkey:9-alpine,並從 ghcr.io/paperless-ngx/paperless-ngx:latest 取得應用程式。

先決條件

  • 具備 sudo 存取權的 Ubuntu 24.04 KVM VPS,且已安裝 Docker 與 Compose 外掛。如果這部分不熟悉,請先閱讀 VPS 的 Docker Compose 基礎知識,再返回此處。
  • 具備一個 A record 指向該 VPS 的網域名稱。Paperless 不會接受透過 HTTPS 對尚未設定的主機名稱進行登入,因此這項設定的重要性比預期更早。
  • 記憶體是實際限制。PostgreSQL、Valkey、Granian 網頁伺服器與 Tesseract OCR worker 同時常駐時,輕度使用約需 2 GB。如果預計匯入數百份掃描文件的待處理資料,請配置 4 GB,因為大型多頁 PDF 執行 OCR 時會產生記憶體尖峰,可能導致 worker 被 kernel 的 out-of-memory killer 終止。
  • 磁碟空間:封存資料會儲存兩份,分別是原始檔案與 OCR 處理後的封存 PDF,因此請預留約為掃描檔總大小 2 倍的空間。

取得官方 compose 檔案

系統提供互動式安裝程式:

bash -c "$(curl --location --silent --show-error https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"

該程式會詢問設定問題並自動產生檔案。手動執行則僅需四個指令,且能讓您清楚掌握所有檔案位置,這對於需要維護的伺服器至關重要。

mkdir -p ~/paperless && cd ~/paperless
curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.postgres.yml
curl -fsSL -o docker-compose.env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.env
curl -fsSL -o .env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/.env

各變體版本位於相同目錄中:docker-compose.sqlite.yml、docker-compose.mariadb.yml 以及各版本的 -tika 變體。新安裝建議選擇 postgres。SQLite 適用於數百份文件,但全文檢索索引的效能會比 PostgreSQL 更早出現瓶頸。

.env 檔案內含一行內容:COMPOSE_PROJECT_NAME=paperless。此名稱會成為每個容器與儲存卷(volume)的前綴,請勿刪除該檔案,否則 docker compose down -v 將無法找到您的資料。

首次啟動前設定 docker-compose.env

有兩項設定不可省略。請使用專案文件指定的命令產生 secret key:

python3 -c "import secrets; print(secrets.token_urlsafe(64))"

接著編輯 docker-compose.env:

PAPERLESS_SECRET_KEY=<the long string you just generated>
PAPERLESS_URL=https://paperless.example.com
PAPERLESS_TIME_ZONE=Europe/Berlin
PAPERLESS_OCR_LANGUAGE=deu+eng
USERMAP_UID=1000
USERMAP_GID=1000

PAPERLESS_SECRET_KEY 預設為字面值 change-me。此值會用來簽署工作階段 token。目前版本會將該預留值視為未設定:當金鑰遺失、空白或仍為 change-me 時,paperless 會拒絕啟動。因此,必須先替換該值,stack 才能啟動。請在首次啟動前設定,因為之後變更會讓所有使用者登出。

PAPERLESS_URL 是最容易節省排查時間的設定。Paperless 是 Django 應用程式,而 Django 會同時檢查 Host 標頭,以及登入表單中瀏覽器回報的來源。設定 PAPERLESS_URL 後,系統會自動將您的位址加入 ALLOWED_HOSTS、CORS_ALLOWED_HOSTS 和 CSRF_TRUSTED_ORIGINS。若留白並將網域指向這台主機,登入頁面仍會載入,因為 PAPERLESS_ALLOWED_HOSTS 預設為 *;但透過 HTTPS 提交登入表單時,會因 CSRF verification failed. Request aborted. 而失敗,因為您的網域不是受信任的來源。設定值後方不要加斜線,也不要包含路徑。

USERMAP_UID 和 USERMAP_GID 會指定容器執行時使用的使用者。請將它們設為您自己的帳號,並使用 id -u 和 id -g 查詢帳號資訊。若兩者不一致,您複製到 consume 資料夾的檔案會因 consumer 無法讀取而無法匯入,日誌也會顯示權限錯誤。

啟動堆疊並建立第一個使用者

docker compose pull
docker compose up -d
docker compose run --rm webserver createsuperuser
docker compose logs -f webserver

createsuperuser 會要求輸入使用者名稱、電子郵件和密碼。系統沒有預設登入資訊。若略過此步驟,第一個開啟網頁介面的使用者會被要求建立 superuser。當 8000 埠仍對網際網路開放時,該使用者可能不是你。因此,請立即從 shell 建立帳戶。等待日誌出現伺服器正在監聽 8000 埠的訊息後,再使用瀏覽器連線。第一次啟動也會執行資料庫 migration,通常需要 1 到 2 分鐘。

先在本機檢查,不要急著設定網域:

curl -I http://127.0.0.1:8000

302 將你重新導向至 /accounts/login/,表示堆疊運作正常。

在前方設定 HTTPS

預設的 compose 檔案會發布 8000:8000,並繫結至所有介面。在公開 VPS 上,任何找到該位址的人都能透過未加密的 HTTP 取得整個文件檔案。請將連接埠設定改為只繫結至 loopback:

    ports:
      - "127.0.0.1:8000:8000"

接著在 reverse proxy 中終止 TLS(transport layer security),再將請求轉送至 127.0.0.1:8000。如果這是該主機上唯一的應用程式,使用任何具備 ACME(automatic certificate management environment)用戶端的 proxy 即可。如果要在同一組憑證設定後方執行多個容器,請依照 多個 Docker Compose 應用程式的 Traefik reverse proxy 模式,將 webserver 服務連接至 proxy network,且完全不要發布連接埠。

無論使用哪個 proxy,登入表單的來源檢查都是 HTTPS 設定最容易出錯的地方。除非設定 PAPERLESS_PROXY_SSL_HEADER,否則 Paperless 會忽略 X-Forwarded-Proto。此設定預設為關閉,因此 Django 會將所有經過 proxy 的請求視為未加密的 HTTP,而瀏覽器傳送的 https:// origin 只有在列入信任清單時才會通過。將 PAPERLESS_URL 設為你在瀏覽器中輸入的確切 https:// 位址,才能將它加入該清單。未設定時,頁面看起來正常,但會出現 CSRF verification failed. Request aborted.。

此外,請提高 proxy 的上傳大小限制。透過將 request body 限制為 1 MB 的 proxy 上傳 40 MB 掃描檔時,請求會在 paperless 收到之前就遭到拒絕,瀏覽器只會顯示一般性的上傳失敗。

consume 目錄的運作方式

compose 檔案會將 ./consume 從 compose 目錄繫結掛載至容器。放入其中的任何檔案都會被匯入,之後從該目錄刪除,因為檔案已由 paperless 管理並存放在 media volume 中。

cp ~/scan-2026-07-14.pdf ~/paperless/consume/
docker compose logs -f webserver

您應會看到 consumer 取得檔名、執行 OCR,最後顯示文件已新增的訊息。單頁掃描的完整流程只需數秒,長篇文件則可能需要 1 分鐘以上。

有兩項設定會改變檔案的搜尋方式。PAPERLESS_CONSUMER_RECURSIVE=true 會讓 paperless 搜尋子目錄;PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true 則會將各子目錄名稱轉換為 tag。因此,將檔案放入 consume/invoices/2026/ 後,會為其加上 invoices 和 2026 tag。這是您能建立的最低成本歸檔系統。

偵測是另一個部分。根據預設,PAPERLESS_CONSUMER_POLLING_INTERVAL 為 0,表示 paperless 使用原生檔案系統通知,檔案變更會立即觸發通知。在網路檔案系統上,這些通知並不可靠。如果您的 consume 目錄是 NFS 或 SMB share,讓網路掃描器能夠寫入其中,檔案可能會一直未被偵測。解決方式是將間隔設為正整數秒,讓 paperless 改為掃描該目錄。

OCR 語言與其成本

PAPERLESS_OCR_LANGUAGE 接受 3 個字母的 Tesseract 語言代碼,預設為 eng。使用加號組合多種語言,例如 deu+eng。之後,Tesseract 會在每一頁使用列出的所有語言,因此每增加一種語言,每次掃描都會增加 CPU 使用時間。對共用 vCPU 的 VPS 而言,這可能使掃描時間從 10 秒延長至 1 分鐘。只列出文件實際使用的語言。

此映像檔內建英文、德文、義大利文、西班牙文與法文。若需要其他語言,請將語言加入 PAPERLESS_OCR_LANGUAGES,以空格分隔,例如 PAPERLESS_OCR_LANGUAGES=tur ces,然後重新啟動。容器會在啟動時下載 Tesseract 資料套件,因此變更後的第一次啟動會較慢。如果您要搜尋的是相片中的繁體中文字,例如招牌或菜單照片,就不必交給 Paperless 處理;相片庫若放在 Immich,可參考Immich 中文搜尋的 CLIP 模型與 OCR 設定,並先估算這些功能在 VPS 上額外佔用的記憶體。

備份資料庫與媒體檔案

PostgreSQL 執行期間複製 Docker volume,取得的備份可能無法還原。Paperless 提供專用的匯出工具,會將文件及所有中繼資料的 JSON manifest 寫入 ./export bind mount:

docker compose exec -T webserver document_exporter ../export --delete --no-progress-bar

--delete 會移除與目前文件不再相符的匯出檔案,讓資料夾維持鏡像狀態,不會無限增長。--no-progress-bar 可在 cron 執行時保持輸出整潔,-T 則可避免 Compose 要求 cron 不具備的終端機。

在新的 stack 上,還原作業可針對同一個資料夾執行 document_importer,因此只需妥善保管匯出目錄即可。依排程將它傳送至異地,使用 來自 VPS 的加密、去重 restic 備份;並先執行匯出,讓 restic 不會擷取尚未寫入完成的封存檔。

驗證備份時,確認 export/manifest.json 存在,並確認檔案數量與介面中的文件數量相符。從未列出內容的備份不算備份。每晚匯出若悄悄開始失敗,情況更糟;因此讓 cron 工作將結束狀態傳送至 你自己的 ntfy server,這樣會在故障發生的那一週得知,而不是等到需要還原的那一天。

FAQ

為什麼將網域指向服務後,每個頁面都回傳「錯誤請求 (400)」?

使用預設檔案時不應發生這種情況,因為 PAPERLESS_ALLOWED_HOSTS 預設為 *。容器日誌中的 400 搭配 DisallowedHost,表示 PAPERLESS_ALLOWED_HOSTS 已設定為不包含您網域的清單。請在 docker-compose.env 中設定 PAPERLESS_URL=https://paperless.example.com,且結尾不要加斜線;paperless 會將該主機名稱加入清單。您也可以移除 PAPERLESS_ALLOWED_HOSTS 這一行。接著執行 docker compose up -d 重新建立容器。只修改環境變數檔案不會生效,因為執行中的容器會沿用啟動時取得的環境。

我將 PDF 放入 consume 資料夾後沒有任何反應。問題在哪裡?

先檢查 docker compose logs webserver。權限錯誤表示 USERMAP_UID 和 USERMAP_GID 與檔案擁有者的帳號不一致,因此請修正後重新建立容器。完全沒有日誌項目表示檔案事件根本沒有傳入。網路共用上常發生這種情況,因為原生檔案系統通知在該環境中並不可靠。請將 PAPERLESS_CONSUMER_POLLING_INTERVAL 設為類似 30 的值,paperless 便會改為每 30 秒掃描一次資料夾。

我可以使用 SQLite 取代 PostgreSQL 執行 paperless-ngx 嗎?

可以。docker-compose.sqlite.yml 受支援,且使用較少記憶體,適合小型 VPS。取捨會在檔案庫逐漸增大時顯現:當文件達到數千份後,全文搜尋與大量標籤編輯會明顯變慢。之後遷移需要先匯出再匯入,因此如果預期檔案庫會持續增長,現在就應選擇 PostgreSQL。

掃描檔案庫實際需要多少磁碟空間?

大約是來源檔案大小的 2 倍。Paperless 會保留未修改的原始檔,並儲存另一份包含可搜尋文字層的 OCR PDF,以及少量縮圖。200 KB 的純文字掃描檔仍然很小。30 MB 的長篇彩色合約掃描檔,約會佔用 60 MB。若將匯出目錄保存在同一顆磁碟上,還要加上該目錄的空間,整個檔案庫會佔用約 3 倍的磁碟空間。

我需要 Tika 和 Gotenberg 容器嗎?

只有在您希望將 Word、Excel 或 OpenDocument 檔案與 PDF 一起建立索引時才需要。這些容器會將上述格式轉換為 PDF,讓 paperless 能夠對其執行 OCR 和搜尋。它們也會多增加 2 個執行中的容器,並使用數百 MB 的記憶體。因此,如果您歸檔的內容全都是 PDF 或影像,小型主機可以略過這些容器。

這篇文章對您有幫助嗎?

#paperless-ngx#documents#self-hosting#docker#ocr