Paperless-ngx sa VPS: self-host na document archive
I-set up ang Paperless-ngx sa VPS gamit ang Docker Compose, official Postgres stack, PAPERLESS_URL, consume folder, OCR languages, HTTPS, at backups.
Ano ang binubuo mo
Ginagawang searchable archive ng Paperless-ngx sa isang VPS ang isang folder ng mga na-scan na dokumento. Maglagay ka ng PDF sa isang watched directory. Patatakbuhin ito ng server sa OCR (optical character recognition), ie-extract ang text, huhulaan ang petsa at correspondent, at ifa-file ang dokumento. Ang installation ay isang Docker Compose file na may apat na service. Pagkatapos nito, configuration na ang lahat. Karamihan ng guide na ito ay nakatuon dito dahil dito kadalasang nasisira ang mga installation. Hindi ito photo library. Walang magagawa ang OCR at correspondent guessing para sa isang folder ng mga JPEG mula sa bakasyon. Ilagay ang mga iyon sa isang photo server na para sa mga ito at gamitin ang Paperless para sa mga dokumento.
Ang Paperless-ngx ay ang pinapanatiling community fork ng orihinal na Paperless. Libre ito, self-hosted, at iniimbak ang iyong mga dokumento bilang plain files sa disk, kaya hindi ka mawawalan ng access sa sarili mong archive. Kapag pinatakbo ito sa isang VPS sa halip na sa home box, maa-access mo ang iyong mga scan kahit saan nang hindi nagbubukas ng port sa home router, at mahusay itong ipares sa isang private Nextcloud instance para sa mga file na hindi papel. Saklaw din ng parehong lohika ang desktop na nakakonekta sa iyong scanner, dahil hinahayaan ka ng sarili mong RustDesk relay sa VPS na iyon na kontrolin ang machine na iyon mula sa ibang lugar nang hindi rin nagbubukas ng port sa router.
Ano talaga ang pinapatakbo ng stack
Nagsisimula ang official compose file ng apat na container. Kapag alam mo ang gamit ng bawat isa, mas madaling basahin ang logs.
webserver: ang paperless-ngx image mismo. Pinapatakbo nito ang web interface, API, consumer na nagmo-monitor sa input folder mo, at mga Celery task worker na nagsasagawa ng OCR.db: PostgreSQL. Dito nakaimbak ang metadata, tags, correspondents, at mga table ng full-text search index. Hindi dito nakaimbak ang mga PDF mo.broker: Valkey, isang Redis-compatible na key-value store. Ito ang task queue sa pagitan ng web process at mga worker.gotenbergattika: optional lamang at ginagamit sa mga-tikacompose variant. Kino-convert ng mga ito ang Office document (.docx,.xlsx,.odt) sa PDF para ma-index ng paperless.
Noong July 2026, naka-pin sa postgres compose file ang docker.io/library/postgres:18 at docker.io/valkey/valkey:9-alpine, at kinukuha nito ang app mula sa ghcr.io/paperless-ngx/paperless-ngx:latest.
Mga Kinakailangan
- Isang Ubuntu 24.04 KVM VPS na may sudo access, at naka-install na ang Docker kasama ang Compose plugin. Kung bago sa iyo ang bahaging ito, magsimula sa mga pangunahing kaalaman sa Docker Compose para sa VPS at bumalik dito.
- Isang domain name na may A record na nakaturo sa VPS. Tumanggi ang Paperless na mag-serve sa hostname na hindi nito nakikilala, kaya mas maaga itong kailangang i-configure kaysa sa inaasahan mo.
- Ang memory ang pangunahing limitasyon. Ang PostgreSQL, Valkey, gunicorn, at isang Tesseract OCR worker ay maaaring sabay-sabay na tumakbo sa 2 GB para sa magaan na paggamit. Maglaan ng 4 GB kung plano mong mag-import ng backlog na daan-daang scan, dahil ang OCR ng malaking multi-page PDF ang nagdudulot ng memory spike na maaaring magpa-kill sa worker ng kernel out-of-memory killer.
- Disk: dalawang beses nase-save ang archive mo—ang original file at isang OCR'd archive PDF—kaya maglaan ng humigit-kumulang doble sa laki ng mga scan mo.
Kunin ang opisyal na compose files
May interactive installer:
bash -c "$(curl --location --silent --show-error https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"Nagtatanong ito at isinusulat ang mga file para sa iyo. Apat na command lang ang manu-manong paraan, at malalaman mo kung nasaan ang lahat. Ito ang kailangan mo sa server na ikaw ang magme-maintain.
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/.envNasa iisang directory ang mga variant: docker-compose.sqlite.yml, docker-compose.mariadb.yml, at isang -tika version ng bawat isa. Piliin ang postgres para sa bagong install. Ayos ang SQLite para sa ilang daang dokumento, pero bumabagal ang full-text search index bago pa bumagal ang PostgreSQL.
May isang linya ang file na .env: COMPOSE_PROJECT_NAME=paperless. Nagiging prefix ang pangalang ito sa bawat container at volume. Huwag itong i-delete at pagkatapos ay magtaka kung bakit hindi mahanap ng docker compose down -v ang iyong data.
I-configure ang docker-compose.env bago ang unang pag-start
Hindi optional ang dalawang setting. I-generate ang secret key gamit ang command na nakadokumento sa project:
python3 -c "import secrets; print(secrets.token_urlsafe(64))"Pagkatapos, i-edit ang 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=1000Ang PAPERLESS_SECRET_KEY ay may literal na value na change-me bilang default. Nilalagdaan nito ang session cookies, kaya kung iiwan ito, maaaring gumawa ng session ang sinumang nakaaalam ng default. I-set ito bago ang unang pag-start, dahil kapag binago ito sa bandang huli, malala-log out ang lahat ng user.
Ang PAPERLESS_URL ang setting na makakatipid sa iyo ng isang oras. Django application ang Paperless, at vine-validate ng Django ang Host header ng bawat request. I-set ang PAPERLESS_URL, at awtomatiko nitong pupunan ang ALLOWED_HOSTS, CORS_ALLOWED_HOSTS, at CSRF_TRUSTED_ORIGINS para sa iyo. Kapag iniwan itong walang laman, nag-point ng domain sa server, at bumalik ang bawat page ng Bad Request (400), makikita ang DisallowedHost sa container log. Isulat ito nang walang trailing slash at walang path.
Itinatakda ng USERMAP_UID at USERMAP_GID ang user na gagamitin ng container sa pagtakbo. Itugma ang mga ito sa sarili mong account, na mabe-verify gamit ang id -u at id -g. Kung hindi magtutugma ang mga ito, hindi mababasa ng consumer ang mga file na kinopya mo sa consume folder, at permission error ang lalabas sa log sa halip na import.
Simulan ang stack at gawin ang unang user
docker compose pull
docker compose up -d
docker compose run --rm webserver createsuperuser
docker compose logs -f webserverHumihingi ang createsuperuser ng username, email, at password. Walang default login, kaya kung lalaktawan mo ang hakbang na ito, mapupunta ka sa sign-in page na walang tatanggapin na login. Hintaying lumabas sa log ang linyang nagsasabing nakikinig ang server sa port 8000 bago gamitin ang browser. Sa unang pagsisimula, nagpapatakbo rin ito ng database migrations, na karaniwang tumatagal ng isa o dalawang minuto.
Suriin muna ito nang lokal bago gumamit ng domain:
curl -I http://127.0.0.1:8000Ibig sabihin ng 302 redirect sa /accounts/login/ na maayos ang takbo ng stack.
Ilagay ang HTTPS sa harap nito
Ang stock compose file ay nagpa-publish ng 8000:8000, na nagbi-bind sa lahat ng interface. Sa public VPS, inilalantad nito ang buong document archive mo sa plain HTTP sa sinumang makahanap ng address. Baguhin ang port line upang loopback lamang ang i-bind:
ports:
- "127.0.0.1:8000:8000"Pagkatapos, i-terminate ang TLS (transport layer security) sa isang reverse proxy at i-forward ito sa 127.0.0.1:8000. Kung ito lamang ang app sa server, sapat na ang anumang proxy na may ACME (automatic certificate management environment) client. Kung nagpapatakbo ka ng ilang container sa iisang certificate setup, sundin ang Traefik reverse proxy pattern para sa maraming Docker Compose app at i-attach ang webserver service sa proxy network nang walang published port.
Anuman ang proxy na gamitin mo, dapat nitong ipadala ang X-Forwarded-Proto: https. Kung wala ito, ipinapalagay ng Django na dumating ang request sa HTTP, mabibigo ang origin check sa login form, at makakakuha ka ng CSRF verification failed. Request aborted. sa page na mukhang tama. Ang kabilang bahagi ng fix na ito ay ang pagtatakda ng PAPERLESS_URL sa eksaktong https:// address na tina-type mo sa browser.
Itaas din ang upload size limit ng proxy. Ang 40 MB na scan na dumadaan sa proxy na naglilimita sa request body sa 1 MB ay mare-reject bago pa ito makita ng paperless, at generic upload failure ang iuulat ng browser.
Paano gumagana ang consume directory
Ibinabind-mount ng compose file ang ./consume mula sa compose directory papunta sa container. Anumang ilagay mo roon ay ini-import at pagkatapos ay dine-delete mula sa folder, dahil nasa media volume na ang file at paperless na ang namamahala rito.
cp ~/scan-2026-07-14.pdf ~/paperless/consume/
docker compose logs -f webserverDapat mong makitang kinukuha ng consumer ang filename, nagpapatakbo ng OCR, at nagtatapos sa isang linya na nagsasabing naidagdag ang document. Ilang segundo lamang ang buong proseso para sa one-page scan, pero maaaring umabot ng isang minuto o higit pa para sa mahabang document.
Dalawang setting ang nagbabago kung paano hinahanap ang mga file. Ginagawa ng PAPERLESS_CONSUMER_RECURSIVE=true na maghanap ang paperless sa mga subfolder, at ginagawang tag ng PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true ang pangalan ng bawat subfolder. Kaya kapag naglagay ka ng file sa consume/invoices/2026/, lalagyan ito ng tag na invoices at 2026. Ito ang pinakamurang filing system na mabubuo mo.
Detection ang kabilang bahagi. Bilang default, ang PAPERLESS_CONSUMER_POLLING_INTERVAL ay 0, na nangangahulugang gumagamit ang paperless ng kernel filesystem notifications na agad nagti-trigger. Hindi tumatawid ang mga notification na ito sa network filesystem. Kung NFS o SMB share ang consume folder mo para maisulatan ito ng network scanner, walang made-detect kailanman. Ang solusyon ay itakda ang interval sa positibong bilang ng segundo upang sa halip ay regular na i-scan ng paperless ang folder.
Mga OCR language at ang katumbas na resource cost
Ang PAPERLESS_OCR_LANGUAGE ay tumatanggap ng three-letter Tesseract code, at eng ang default. Pagsamahin ang mga language gamit ang plus sign, gaya ng deu+eng. Susubukan ng Tesseract ang bawat isa at pananatilihin ang pinakamagandang resulta, kaya bawat karagdagang language ay nagpaparami sa CPU time na ginagamit sa bawat page. Sa isang VPS na may shared vCPU, maaaring ito ang pagkakaiba sa pagitan ng scan na natatapos sa loob ng ten seconds at ng scan na umaabot ng one minute. Ilagay lamang ang mga language na aktuwal na ginagamit sa mga dokumento mo.
Kasama sa image ang English, German, Italian, Spanish, at French. Para sa iba pang language, idagdag ito sa PAPERLESS_OCR_LANGUAGES bilang listahang pinaghihiwalay ng spaces, halimbawa PAPERLESS_OCR_LANGUAGES=tur ces, at pagkatapos ay mag-restart. Dina-download ng container ang Tesseract data packs sa startup, kaya mas mabagal ang unang boot pagkatapos ng pagbabagong ito.
I-back up ang database at media
Ang pagkopya sa Docker volumes habang tumatakbo ang PostgreSQL ay maaaring magbigay ng backup na hindi maibabalik. May sarili itong exporter ang Paperless. Nagsusulat ito ng mga document at JSON manifest ng lahat ng metadata sa ./export bind mount:
docker compose exec webserver document_exporter ../export --delete --no-progress-barTinatanggal ng --delete ang mga exported file na hindi na tumutugma sa kasalukuyang document. Kaya nananatiling mirror ang folder sa halip na patuloy na lumaki. Pinananatiling malinis ng --no-progress-bar ang output kapag pinapatakbo ito mula sa cron.
Isinasagawa ang restore gamit ang document_importer laban sa kaparehong folder sa bagong stack. Ibig sabihin, ang export directory lang ang kailangan mong panatilihing ligtas. Ipadala ito sa offsite storage ayon sa schedule gamit ang encrypted at deduplicated na restic backup mula sa iyong VPS, at patakbuhin muna ang export upang hindi makuha ng restic ang archive na hindi pa tapos maisulat.
I-verify ang backup sa pamamagitan ng pag-check kung umiiral ang export/manifest.json at kung tugma ang bilang ng mga file sa bilang ng mga dokumento sa interface. Hindi backup ang isang backup na hindi mo kailanman na-list. Mas masama pa ang nightly export na tahimik na nagsisimulang mag-fail. Kaya ipa-push sa cron job ang exit status nito sa sarili mong ntfy server. Sa ganitong paraan, malalaman mo sa linggong nag-fail ito, sa halip na sa araw na kailangan mo itong i-restore.
FAQ
Bakit nagbabalik ng "Bad Request (400)" ang bawat page matapos kong ituro rito ang domain ko?
Tinanggihan ng Django ang Host header dahil wala ang domain mo sa ALLOWED_HOSTS. Itakda ang PAPERLESS_URL=https://paperless.example.com sa docker-compose.env, nang walang trailing slash, pagkatapos ay patakbuhin ang docker compose up -d upang muling gawin ang container. Walang epekto ang pag-edit lamang sa env file dahil ginagamit pa rin ng tumatakbong container ang environment na itinakda noong nagsimula ito.
Naglagay ako ng PDF sa consume folder pero walang nangyari. Ano ang mali?
Suriin muna ang docker compose logs webserver. Ibig sabihin ng permission error ay hindi tugma ang USERMAP_UID at USERMAP_GID sa account na nagmamay-ari ng file, kaya ayusin ang mga ito at muling gawin ang container. Kung walang lumabas na log line, hindi nakarating ang file event. Nangyayari ito sa network shares dahil hindi tumatawid sa mga ito ang kernel notifications. Itakda ang PAPERLESS_CONSUMER_POLLING_INTERVAL sa gaya ng 30 at sa halip ay isi-scan ng paperless ang folder bawat 30 segundo.
Maaari ko bang patakbuhin ang paperless-ngx gamit ang SQLite sa halip na PostgreSQL?
Oo, suportado ang docker-compose.sqlite.yml at mas kaunti ang memory na ginagamit nito, kaya angkop ito sa maliit na VPS. Lumilitaw ang tradeoff habang lumalaki ang archive: kapansin-pansing bumabagal ang full-text search at maramihang pag-edit ng tags kapag umabot na sa libo-libo ang mga document. Ang paglipat sa ibang database sa hinaharap ay nangangailangan ng export at import, kaya piliin na ngayon ang PostgreSQL kung inaasahan mong patuloy na lalaki ang archive.
Gaano kalaking disk space ang aktuwal na kailangan ng archive ng mga scan?
Humigit-kumulang dalawang beses ng laki ng source files. Pinananatili ng Paperless ang orihinal na file at nag-iimbak ng ikalawang OCR'd PDF na may searchable text layer, kasama ang maliliit na thumbnail. Maliit pa rin ang isang 200 KB na text-only scan. Ang 30 MB na color scan ng mahabang kontrata ay kumokonsumo ng humigit-kumulang 60 MB. Idagdag ang export directory kung pinananatili mo ito sa parehong disk, kaya magiging tatlong beses ng laki sa disk ang parehong archive.
Kailangan ko ba ang Tika at Gotenberg containers?
Kailangan lamang ang mga ito kung gusto mong ma-index ang Word, Excel, o OpenDocument files kasama ng iyong mga PDF. Kino-convert ng mga ito ang mga format na iyon sa PDF upang ma-OCR at ma-search ng paperless. Nagdadagdag din ang mga ito ng dalawa pang tumatakbong container at ilang daang megabytes ng memory, kaya laktawan ang mga ito sa maliit na server kung PDF o image na ang lahat ng ina-archive mo.