SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-10-24

Cara Pasang Paperless-ngx di VPS Menggunakan Docker

Ketahui cara memasang Paperless-ngx pada VPS dengan Docker Compose. Panduan ini merangkumi konfigurasi Postgres, PAPERLESS_URL, OCR, HTTPS, serta strategi sandaran data.

Apa yang anda sedang bina

Paperless-ngx pada VPS menukarkan folder dokumen yang diimbas menjadi arkib yang boleh dicari. Anda memasukkan fail PDF ke dalam direktori yang dipantau, pelayan akan menjalankan OCR (optical character recognition) ke atasnya, mengekstrak teks, meneka tarikh serta pengirim, dan memfailkannya. Pemasangan ini terdiri daripada satu fail Docker Compose dengan empat servis. Segala proses selepas itu adalah konfigurasi, dan panduan ini menumpukan sebahagian besar kandungannya di situ, kerana di situlah pemasangan biasanya gagal. Ia bukanlah pustaka foto: OCR dan peneka pengirim tidak berfungsi untuk folder gambar JPEG percutian, jadi letakkan fail tersebut di pelayan foto yang dibina untuk tujuan itu dan simpan Paperless khusus untuk dokumen kertas. Video juga tertakluk kepada batasan yang sama: koleksi filem yang telah disalin (ripped) lebih sesuai diletakkan pada pelayan media, di mana sesuatu seperti antaramuka Jellyfin yang diubah suai seperti kedai sewa filem tahun 90-an menjadikan proses melayari sebagai fokus utama berbanding carian.

Paperless-ngx ialah fork komuniti yang diselenggara daripada projek asal Paperless. Ia adalah percuma, dihoskan sendiri, dan menyimpan dokumen anda sebagai fail biasa pada cakera, jadi anda tidak akan terkunci daripada arkib anda sendiri. Menjalankannya pada VPS berbanding mesin di rumah bermakna imbasan anda boleh diakses dari mana-mana sahaja tanpa perlu membuka port pada penghala rumah anda, dan ia sangat sesuai digandingkan dengan instans Nextcloud peribadi untuk fail yang bukan berbentuk dokumen kertas. Logik yang sama terpakai untuk komputer meja yang disambungkan dengan pengimbas anda, memandangkan relay RustDesk anda sendiri pada VPS tersebut membolehkan anda mengawal mesin itu dari tempat lain tanpa perlu menebuk lubang keselamatan pada penghala.

Perkara yang sebenarnya dijalankan oleh stack

Fail compose rasmi memulakan empat kontena, dan memahami fungsi setiap satu menjadikan log lebih mudah dibaca.

  • webserver: imej paperless-ngx itu sendiri. Ia menjalankan antara muka web, API, pengguna yang memantau folder input anda, dan pekerja tugas Celery yang melakukan OCR.
  • db: PostgreSQL. Ia menyimpan metadata, tag, koresponden, dan jadual indeks carian teks penuh. Ia tidak menyimpan fail PDF anda.
  • broker: Valkey, stor nilai-kunci yang serasi dengan Redis. Ia merupakan baris gilir tugas antara proses web dan pekerja.
  • gotenberg dan tika: pilihan, hanya dalam varian compose -tika. Ia menukarkan dokumen Office (.docx, .xlsx, .odt) kepada PDF supaya paperless boleh mengindeksnya.

Sehingga Oktober 2026, fail compose postgres menetapkan docker.io/library/postgres:18 dan docker.io/valkey/valkey:9-alpine, serta menarik aplikasi daripada ghcr.io/paperless-ngx/paperless-ngx:latest.

Prasyarat

  • Sebuah VPS KVM Ubuntu 24.04 dengan akses sudo, serta Docker dengan pemalam Compose yang telah dipasang. Jika bahagian ini baharu bagi anda, mulakan dengan asas Docker Compose untuk VPS dan kembali semula ke sini.
  • Nama domain dengan rekod A yang menghala ke VPS tersebut. Paperless tidak akan menerima daftar masuk melalui HTTPS pada nama hos yang tidak didaftarkan, jadi perkara ini penting lebih awal daripada yang anda jangkakan.
  • Memori merupakan kekangan sebenar. PostgreSQL, Valkey, pelayan web Granian dan pekerja OCR Tesseract yang berjalan serentak memerlukan 2 GB untuk penggunaan ringan. Sediakan 4 GB jika anda bercadang untuk mengimport timbunan ratusan imbasan, kerana proses OCR pada fail PDF berbilang halaman yang besar akan menyebabkan lonjakan memori yang mengakibatkan pekerja tersebut ditamatkan oleh kernel (out-of-memory killer).
  • Cakera: arkib anda disimpan sebanyak dua kali, iaitu fail asal dan fail PDF arkib yang telah melalui OCR, jadi sediakan ruang simpanan kira-kira dua kali ganda saiz imbasan anda.

Dapatkan fail compose rasmi

Terdapat pemasang interaktif:

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

Ia akan menanyakan beberapa soalan dan menulis fail tersebut untuk anda. Melakukannya secara manual hanya memerlukan empat arahan dan memberikan anda kefahaman tentang lokasi setiap fail, yang merupakan perkara penting bagi pelayan yang akan anda selenggara.

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

Varian tersebut berada dalam direktori yang sama: docker-compose.sqlite.yml, docker-compose.mariadb.yml, dan versi -tika bagi setiap satunya. Pilih postgres untuk pemasangan baharu. SQLite memadai untuk beberapa ratus dokumen, namun indeks carian teks penuh akan menjadi perlahan jauh lebih awal berbanding PostgreSQL.

Fail .env mengandungi satu baris, iaitu COMPOSE_PROJECT_NAME=paperless. Nama tersebut menjadi awalan bagi setiap kontena dan volum, jadi jangan padamkannya dan kemudian tertanya-tanya mengapa docker compose down -v tidak dapat menemui data anda.

Konfigurasikan docker-compose.env sebelum permulaan pertama

Dua tetapan adalah wajib. Jana kunci rahsia menggunakan arahan yang didokumenkan oleh projek:

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

Kemudian sunting 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 dihantar dengan nilai literal change-me. Ia menandatangani token sesi, dan keluaran semasa menganggap pemegang tempat tersebut sebagai tidak ditetapkan: paperless enggan bermula selagi kunci itu tiada, kosong atau masih change-me, jadi stack tidak akan naik sehingga anda menggantikannya. Tetapkan ia sebelum permulaan pertama, kerana menukarnya kemudian akan mengeluarkan log masuk setiap pengguna.

PAPERLESS_URL adalah tetapan yang menjimatkan masa anda. Paperless ialah aplikasi Django, dan Django menyemak kedua-dua pengepala Host dan, pada borang daftar masuk, asal (origin) yang dilaporkan oleh pelayar. Tetapkan PAPERLESS_URL dan ia akan menambah alamat anda ke ALLOWED_HOSTS, CORS_ALLOWED_HOSTS dan CSRF_TRUSTED_ORIGINS untuk anda. Jika dibiarkan kosong, dan anda menghalakan domain ke pelayan, halaman daftar masuk masih akan dimuatkan kerana PAPERLESS_ALLOWED_HOSTS secara lalai adalah *, tetapi penghantaran melalui HTTPS akan gagal dengan CSRF verification failed. Request aborted. kerana domain anda bukan asal yang dipercayai. Tuliskan ia tanpa garis miring (trailing slash) dan tanpa path.

USERMAP_UID dan USERMAP_GID menetapkan pengguna yang menjalankan container tersebut. Padankan ia dengan akaun anda sendiri, yang boleh disemak dengan id -u dan id -g. Jika ia tidak sepadan, fail yang anda salin ke dalam folder consume tidak boleh dibaca oleh consumer, dan log akan menunjukkan ralat kebenaran (permission error) dan bukannya import.

Mulakan stack dan cipta pengguna pertama

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

createsuperuser akan meminta nama pengguna, e-mel dan kata laluan. Tiada log masuk lalai. Jika anda melangkau langkah ini, antara muka web akan meminta sesiapa sahaja yang membukanya terlebih dahulu untuk mencipta pengguna super. Memandangkan port 8000 masih terbuka kepada internet, orang tersebut mungkin bukan anda, jadi cipta akaun daripada shell dengan segera. Tunggu sehingga baris log melaporkan bahawa pelayan sedang mendengar pada port 8000 sebelum anda mencuba pelayar web. Permulaan pertama juga akan menjalankan migrasi pangkalan data, yang mengambil masa satu atau dua minit.

Semak secara tempatan sebelum melibatkan domain:

curl -I http://127.0.0.1:8000

302 yang mengubah hala ke /accounts/login/ bermakna stack tersebut dalam keadaan sihat.

Letakkan HTTPS di hadapannya

Fail compose standard menerbitkan 8000:8000, yang mengikat pada setiap antara muka. Pada VPS awam, ini menghidangkan seluruh arkib dokumen anda melalui HTTP biasa kepada sesiapa sahaja yang menemui alamat tersebut. Tukar baris port untuk mengikat pada loopback sahaja:

    ports:
      - "127.0.0.1:8000:8000"

Kemudian tamatkan TLS (transport layer security) dalam reverse proxy dan halakan ke 127.0.0.1:8000. Jika ini satu-satunya aplikasi pada pelayan, mana-mana proksi dengan klien ACME (automatic certificate management environment) sudah memadai. Jika anda menjalankan beberapa kontena di belakang satu persediaan sijil, ikuti corak reverse proxy Traefik untuk berbilang aplikasi Docker Compose dan lampirkan servis webserver pada rangkaian proksi tanpa sebarang port yang diterbitkan.

Walau apa pun proksi yang anda gunakan, semakan origin pada borang log masuk adalah tempat di mana persediaan HTTPS sering gagal. Paperless mengabaikan X-Forwarded-Proto melainkan anda menetapkan PAPERLESS_PROXY_SSL_HEADER, yang dimatikan secara lalai, jadi Django menganggap setiap permintaan yang diproksi sebagai HTTP biasa, dan origin https:// yang dihantar oleh pelayar anda hanya akan diterima jika ia disenaraikan sebagai dipercayai. PAPERLESS_URL yang ditetapkan kepada alamat https:// tepat yang anda taip dalam pelayar adalah perkara yang memasukkannya ke dalam senarai tersebut. Tanpanya, anda akan mendapat CSRF verification failed. Request aborted. pada halaman yang kelihatan betul.

Tingkatkan juga had saiz muat naik proksi. Imbasan 40 MB melalui proksi yang mengehadkan saiz badan kepada 1 MB akan ditolak sebelum paperless sempat menerimanya, dan pelayar akan melaporkan kegagalan muat naik yang umum.

Cara direktori consume berfungsi

Fail compose melakukan bind-mount pada ./consume dari direktori compose ke dalam kontena. Apa-apa sahaja yang anda letakkan di sana akan diimport dan kemudian dipadamkan daripada folder tersebut, kerana fail itu kini berada dalam volum media di bawah pengurusan paperless.

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

Anda sepatutnya melihat consumer mengesan nama fail, menjalankan OCR, dan selesai dengan baris yang melaporkan dokumen telah ditambah. Keseluruhan kitaran ini mengambil masa beberapa saat untuk imbasan satu halaman dan boleh mencecah seminit atau lebih untuk dokumen yang panjang.

Dua tetapan mengubah cara fail ditemui. PAPERLESS_CONSUMER_RECURSIVE=true menyebabkan paperless mencari di dalam subfolder, dan PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true menukarkan setiap nama subfolder menjadi tag, jadi meletakkan fail ke dalam consume/invoices/2026/ akan memberikan tag invoices dan 2026. Itu adalah sistem pemfailan paling murah yang pernah anda bina.

Pengesanan adalah bahagian yang satu lagi. Secara lalai PAPERLESS_CONSUMER_POLLING_INTERVAL ditetapkan kepada 0, bermakna paperless menggunakan pemberitahuan sistem fail asli, yang dicetuskan serta-merta. Pemberitahuan tersebut tidak boleh dipercayai pada sistem fail rangkaian. Jika folder consume anda ialah perkongsian NFS atau SMB supaya pengimbas rangkaian boleh menulis kepadanya, fail mungkin berada di sana tanpa dikesan, dan penyelesaiannya adalah dengan menetapkan selang masa kepada nombor saat yang positif supaya paperless mengimbas folder tersebut sebagai ganti.

Bahasa OCR dan kosnya

PAPERLESS_OCR_LANGUAGE mengambil kod Tesseract tiga huruf, dengan eng sebagai tetapan lalai. Gabungkan bahasa dengan tanda tambah, seperti dalam deu+eng. Tesseract kemudian akan memproses setiap bahasa yang disenaraikan pada setiap halaman, jadi setiap bahasa tambahan akan menambah masa CPU bagi setiap imbasan. Pada VPS vCPU kongsi, ini merupakan perbezaan antara imbasan yang selesai dalam sepuluh saat dengan imbasan yang mengambil masa seminit. Senaraikan hanya bahasa yang digunakan dalam dokumen anda.

Imej ini menyertakan bahasa Inggeris, Jerman, Itali, Sepanyol, dan Perancis. Untuk bahasa lain, tambahkan bahasa tersebut ke dalam PAPERLESS_OCR_LANGUAGES sebagai senarai yang dipisahkan oleh ruang, contohnya PAPERLESS_OCR_LANGUAGES=tur ces, kemudian mulakan semula. Kontena akan memuat turun pek data Tesseract semasa permulaan, jadi but pertama selepas perubahan tersebut akan menjadi lebih perlahan.

Sandarkan pangkalan data dan media

Menyalin Docker volumes semasa PostgreSQL sedang berjalan akan menghasilkan sandaran yang mungkin tidak boleh dipulihkan. Paperless menyediakan pengeksportnya sendiri, yang menulis dokumen berserta manifes JSON bagi semua metadata ke dalam bind mount ./export:

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

--delete membuang fail yang dieksport yang tidak lagi sepadan dengan dokumen semasa, supaya folder tersebut kekal sebagai cermin dan bukannya terus membesar. --no-progress-bar memastikan output bersih apabila ini dijalankan daripada cron, dan -T menghalang Compose daripada meminta terminal yang tidak dimiliki oleh cron.

Pemulihan dilakukan dengan document_importer terhadap folder yang sama pada stack baharu, yang bermaksud direktori eksport adalah satu-satunya perkara yang perlu anda simpan dengan selamat. Hantarkannya ke luar tapak mengikut jadual dengan sandaran restic yang disulitkan dan dinyahduplikasi daripada VPS anda, dan jalankan eksport terlebih dahulu supaya restic tidak menangkap arkib yang ditulis separuh jalan.

Sahkan sandaran dengan menyemak bahawa export/manifest.json wujud dan kiraan fail sepadan dengan kiraan dokumen anda dalam antara muka. Sandaran yang tidak pernah anda senaraikan bukanlah sandaran. Eksport malam yang gagal secara senyap adalah lebih buruk, jadi tetapkan kerja cron untuk menolak status keluar ke pelayan ntfy anda sendiri supaya anda akan mengetahui pada minggu ia rosak dan bukannya pada hari anda perlu melakukan pemulihan.

FAQ

Mengapa setiap halaman memaparkan "Bad Request (400)" selepas saya menghalakan domain saya kepadanya?

Dengan fail asal, perkara ini tidak sepatutnya berlaku kerana PAPERLESS_ALLOWED_HOSTS ditetapkan secara lalai kepada *. 400 dengan DisallowedHost dalam log kontena bermakna PAPERLESS_ALLOWED_HOSTS telah ditetapkan kepada senarai yang tidak menyertakan domain anda. Tetapkan PAPERLESS_URL=https://paperless.example.com dalam docker-compose.env, tanpa garis miring (trailing slash) di hujungnya, dan paperless akan menambah nama hos tersebut ke dalam senarai, atau buang baris PAPERLESS_ALLOWED_HOSTS. Kemudian, jalankan docker compose up -d untuk mencipta semula kontena tersebut. Menyunting fail env sahaja tidak akan memberikan kesan, kerana kontena yang sedang berjalan mengekalkan persekitaran asal semasa ia dimulakan.

Saya memasukkan fail PDF ke dalam folder consume tetapi tiada apa-apa yang berlaku. Apakah masalahnya?

Periksa docker compose logs webserver terlebih dahulu. Ralat kebenaran (permission error) bermakna USERMAP_UID dan USERMAP_GID tidak sepadan dengan akaun yang memiliki fail tersebut, jadi betulkan tetapan tersebut dan cipta semula kontena. Jika tiada baris log langsung, bermakna peristiwa fail tidak pernah sampai; perkara ini sering berlaku pada perkongsian rangkaian (network shares) kerana pemberitahuan sistem fail natif tidak boleh dipercayai di sana. Tetapkan PAPERLESS_CONSUMER_POLLING_INTERVAL kepada nilai seperti 30 dan paperless akan mengimbas folder tersebut setiap 30 saat sebagai ganti.

Bolehkah saya menjalankan paperless-ngx menggunakan SQLite dan bukannya PostgreSQL?

Ya, docker-compose.sqlite.yml disokong dan menggunakan memori yang lebih sedikit, yang sesuai untuk VPS bersaiz kecil. Kekurangannya akan ketara apabila arkib anda semakin besar: carian teks penuh dan penyuntingan tag secara pukal akan menjadi perlahan apabila mencecah ribuan dokumen. Migrasi pada masa hadapan memerlukan proses eksport dan import, jadi pilihlah PostgreSQL sekarang jika anda menjangkakan arkib anda akan terus berkembang.

Berapakah ruang cakera yang diperlukan oleh arkib imbasan sebenarnya?

Kira-kira dua kali ganda saiz fail asal anda. Paperless mengekalkan fail asal tanpa mengubahnya dan menyimpan fail PDF kedua yang telah melalui proses OCR dengan lapisan teks yang boleh dicari, ditambah dengan imej kecil (thumbnails). Imbasan teks sahaja bersaiz 200 KB kekal kecil. Imbasan berwarna bersaiz 30 MB bagi kontrak yang panjang akan memakan ruang kira-kira 60 MB. Tambahkan direktori eksport jika anda menyimpannya pada cakera yang sama, maka arkib yang sama akan berada di dalam cakera sebanyak tiga kali.

Adakah saya memerlukan kontena Tika dan Gotenberg?

Hanya jika anda mahu fail Word, Excel atau OpenDocument diindeks bersama-sama fail PDF anda. Kontena tersebut menukarkan format berkenaan kepada PDF supaya paperless boleh melakukan OCR dan mencarinya. Ia juga menambah dua lagi kontena yang berjalan serta menggunakan beberapa ratus megabait memori, jadi abaikan kontena tersebut pada pelayan kecil jika semua fail yang anda simpan sudah pun dalam format PDF atau imej.

Adakah artikel ini berguna?

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