SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-08-28

Paperless-ngx di VPS: Arsip Dokumen dengan Docker

Panduan menjalankan paperless-ngx di VPS dengan Docker Compose, termasuk stack Postgres resmi, PAPERLESS_URL, folder consume, bahasa OCR, HTTPS, dan pencadangan.

Yang sedang Anda bangun

Paperless-ngx pada VPS mengubah folder berisi dokumen hasil pemindaian menjadi arsip yang dapat ditelusuri. Anda menempatkan PDF ke dalam direktori yang dipantau, lalu server menjalankan OCR (pengenalan karakter optik), mengekstrak teks, memperkirakan tanggal dan koresponden, lalu mengarsipkannya. Instalasinya menggunakan satu file Docker Compose dengan empat service. Setelah itu, semuanya berupa konfigurasi. Panduan ini menghabiskan sebagian besar isinya untuk konfigurasi karena pada tahap inilah instalasi sering gagal. Paperless-ngx bukan pustaka foto: OCR dan perkiraan koresponden tidak berguna untuk folder berisi JPEG liburan. Simpan file tersebut di server foto yang dibuat untuk keperluan itu, dan gunakan Paperless-ngx untuk dokumen.

Paperless-ngx adalah fork komunitas yang masih dipelihara dari proyek Paperless asli. Aplikasi ini gratis, dapat di-host sendiri, dan menyimpan dokumen Anda sebagai file biasa di disk, sehingga Anda tidak pernah kehilangan akses ke arsip milik sendiri. Menjalankannya pada VPS, bukan pada komputer di rumah, berarti hasil pemindaian dapat diakses dari mana saja tanpa membuka port pada router rumah, dan cocok dipadukan dengan instance Nextcloud privat untuk file yang bukan dokumen kertas. Logika yang sama berlaku untuk desktop yang terhubung ke scanner, karena relay RustDesk milik Anda sendiri pada VPS tersebut memungkinkan Anda mengendalikan mesin itu dari lokasi lain tanpa membuat lubang pada router.

Komponen yang sebenarnya dijalankan oleh stack

File compose resmi menjalankan empat container. Dengan mengetahui fungsi masing-masing, Anda dapat membaca log dengan lebih mudah.

  • webserver: image paperless-ngx itu sendiri. Image ini menjalankan antarmuka web, API, consumer yang memantau folder input, serta worker task Celery yang melakukan OCR.
  • db: PostgreSQL. Komponen ini menyimpan metadata, tag, koresponden, dan tabel indeks pencarian teks lengkap. Komponen ini tidak menyimpan file PDF Anda.
  • broker: Valkey, penyimpanan key-value yang kompatibel dengan Redis. Komponen ini menjadi antrean task antara proses web dan worker.
  • gotenberg dan tika: opsional, hanya tersedia dalam varian compose -tika. Keduanya mengonversi dokumen Office (.docx, .xlsx, .odt) ke PDF agar paperless dapat mengindeksnya.

Per Juli 2026, file compose postgres menetapkan docker.io/library/postgres:18 dan docker.io/valkey/valkey:9-alpine, serta mengambil aplikasi dari ghcr.io/paperless-ngx/paperless-ngx:latest.

Prasyarat

  • VPS KVM Ubuntu 24.04 dengan akses sudo, serta Docker dan plugin Compose yang sudah terpasang. Jika bagian ini masih baru bagi Anda, mulai dengan dasar-dasar Docker Compose untuk VPS, lalu kembali ke sini.
  • Nama domain dengan record A yang mengarah ke VPS. Paperless menolak melayani hostname yang belum ditentukan, jadi hal ini perlu diperhatikan sejak awal.
  • Memori adalah batasan utama. PostgreSQL, Valkey, gunicorn, dan satu worker OCR Tesseract yang berjalan bersamaan masih dapat digunakan dalam 2 GB untuk penggunaan ringan. Gunakan 4 GB jika Anda berencana mengimpor ratusan hasil pemindaian sekaligus, karena OCR pada PDF besar dengan banyak halaman dapat menyebabkan lonjakan penggunaan memori yang membuat worker dihentikan oleh kernel karena kehabisan memori.
  • Disk: arsip Anda disimpan dua kali, yaitu file asli dan PDF arsip hasil OCR. Karena itu, siapkan kapasitas sekitar dua kali ukuran hasil pemindaian Anda.

Dapatkan file compose resmi

Tersedia installer interaktif:

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

Installer ini mengajukan beberapa pertanyaan lalu menulis file untuk Anda. Jika dilakukan secara manual, prosesnya hanya memerlukan empat perintah. Anda juga akan mengetahui lokasi setiap file, yang penting untuk server yang akan Anda pelihara.

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

Semua varian berada di direktori yang sama: docker-compose.sqlite.yml, docker-compose.mariadb.yml, dan versi -tika untuk masing-masing varian. Pilih postgres untuk instalasi baru. SQLite cukup untuk beberapa ratus dokumen, tetapi indeks pencarian teks lengkap menjadi lambat jauh sebelum PostgreSQL.

File .env berisi satu baris, COMPOSE_PROJECT_NAME=paperless. Nama tersebut menjadi awalan untuk setiap container dan volume. Jangan menghapusnya lalu bingung ketika docker compose down -v tidak dapat menemukan data Anda.

Konfigurasikan docker-compose.env sebelum start pertama

Dua pengaturan tidak boleh dikosongkan. Buat secret key dengan perintah yang didokumentasikan oleh proyek:

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

Kemudian edit 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 berisi nilai literal change-me saat pertama kali dirilis. Nilai ini digunakan untuk menandatangani cookie sesi. Jika dibiarkan, siapa pun yang mengetahui nilai default dapat memalsukan sesi. Tetapkan sebelum start pertama, karena perubahan setelahnya akan mengeluarkan semua pengguna dari sesi mereka.

PAPERLESS_URL adalah pengaturan yang dapat menghemat waktu hingga satu jam. Paperless adalah aplikasi Django, dan Django memvalidasi header Host pada setiap permintaan. Tetapkan PAPERLESS_URL agar Django mengisi ALLOWED_HOSTS, CORS_ALLOWED_HOSTS, dan CSRF_TRUSTED_ORIGINS secara otomatis. Jika dibiarkan kosong, arahkan domain ke server tersebut. Setiap halaman kemudian mengembalikan Bad Request (400), dan log container menampilkan DisallowedHost. Tuliskan tanpa garis miring di akhir dan tanpa path.

USERMAP_UID dan USERMAP_GID menentukan pengguna yang digunakan container saat berjalan. Samakan nilainya dengan akun Anda sendiri, yang dapat diperiksa menggunakan id -u dan id -g. Jika nilainya tidak sama, file yang Anda salin ke folder consume tidak dapat dibaca oleh consumer. Log akan menampilkan error izin, bukan proses import.

Mulai stack dan buat pengguna pertama

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

createsuperuser meminta nama pengguna, alamat email, dan kata sandi. Tidak ada login default. Jika langkah ini dilewati, Anda akan berada di halaman login yang tidak akan pernah menerima kredensial apa pun. Tunggu baris log yang melaporkan bahwa server sedang listening pada port 8000 sebelum mencoba membukanya melalui browser. Saat pertama kali dijalankan, proses ini juga melakukan migrasi database. Proses tersebut memerlukan waktu sekitar satu atau dua menit.

Periksa secara lokal sebelum menggunakan domain:

curl -I http://127.0.0.1:8000

Pengalihan 302 ke /accounts/login/ berarti stack berjalan dengan baik.

Letakkan HTTPS di depannya

File compose bawaan memublikasikan 8000:8000, yang terikat ke semua interface. Pada VPS publik, konfigurasi ini menyajikan seluruh arsip dokumen Anda melalui HTTP tanpa enkripsi kepada siapa pun yang menemukan alamatnya. Ubah baris port agar hanya terikat ke loopback:

    ports:
      - "127.0.0.1:8000:8000"

Selanjutnya, lakukan terminasi TLS (transport layer security) pada reverse proxy, lalu teruskan koneksi ke 127.0.0.1:8000. Jika ini satu-satunya aplikasi pada server, proxy apa pun yang memiliki klien ACME (automatic certificate management environment) dapat digunakan. Jika Anda menjalankan beberapa container di balik satu konfigurasi sertifikat, ikuti pola reverse proxy Traefik untuk beberapa aplikasi Docker Compose dan hubungkan service webserver ke jaringan proxy tanpa port yang dipublikasikan sama sekali.

Apa pun proxy yang digunakan, proxy tersebut harus mengirim X-Forwarded-Proto: https. Tanpa header ini, Django menganggap permintaan datang melalui HTTP, pemeriksaan origin pada formulir login gagal, dan Anda mendapatkan CSRF verification failed. Request aborted. pada halaman yang tampak benar. Bagian lain dari perbaikan ini adalah memastikan PAPERLESS_URL diatur ke alamat https:// yang diketik tepat di browser.

Naikkan juga batas ukuran upload pada proxy. Scan berukuran 40 MB yang melewati proxy dengan batas body 1 MB akan ditolak sebelum diterima oleh paperless, dan browser hanya melaporkan kegagalan upload umum.

Cara kerja direktori consume

File compose melakukan bind mount ./consume dari direktori compose ke dalam container. Semua file yang Anda letakkan di sana akan diimpor lalu dihapus dari direktori tersebut, karena file itu kini disimpan di volume media yang dikelola oleh paperless.

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

Anda akan melihat consumer mengambil nama file, menjalankan OCR, lalu selesai dengan baris yang menyatakan bahwa dokumen telah ditambahkan. Seluruh proses ini memerlukan waktu beberapa detik untuk hasil pemindaian satu halaman dan dapat memerlukan waktu satu menit atau lebih untuk dokumen yang panjang.

Dua pengaturan mengubah cara file ditemukan. PAPERLESS_CONSUMER_RECURSIVE=true membuat paperless mencari file di subdirektori, sedangkan PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true mengubah setiap nama subdirektori menjadi tag. Dengan demikian, file yang ditempatkan di consume/invoices/2026/ akan diberi tag invoices dan 2026. Itulah sistem pengarsipan paling sederhana yang dapat Anda buat.

Deteksi adalah bagian lainnya. Secara default, PAPERLESS_CONSUMER_POLLING_INTERVAL bernilai 0. Artinya, paperless menggunakan notifikasi filesystem dari kernel yang aktif secara langsung. Notifikasi tersebut tidak dapat melewati filesystem jaringan. Jika direktori consume Anda berada pada share NFS atau SMB agar network scanner dapat menulis ke sana, tidak ada file yang akan terdeteksi. Solusinya adalah menetapkan interval ke jumlah detik positif agar paperless memindai direktori tersebut.

Bahasa OCR dan biayanya

PAPERLESS_OCR_LANGUAGE menerima kode Tesseract tiga huruf, dengan eng sebagai nilai default. Gabungkan beberapa bahasa dengan tanda plus, seperti pada deu+eng. Tesseract kemudian mencoba setiap bahasa dan mempertahankan hasil terbaik. Karena itu, setiap bahasa tambahan meningkatkan waktu CPU yang digunakan untuk setiap halaman. Pada VPS dengan vCPU bersama, perbedaannya dapat berupa pemindaian yang selesai dalam sepuluh detik atau baru selesai dalam satu menit. Cantumkan hanya bahasa yang benar-benar digunakan dalam dokumen Anda.

Image ini menyertakan bahasa Inggris, Jerman, Italia, Spanyol, dan Prancis. Untuk bahasa lain, tambahkan bahasa tersebut ke PAPERLESS_OCR_LANGUAGES sebagai daftar yang dipisahkan spasi, misalnya PAPERLESS_OCR_LANGUAGES=tur ces, lalu lakukan restart. Container mengunduh paket data Tesseract saat startup, sehingga boot pertama setelah perubahan tersebut akan berlangsung lebih lama.

Cadangkan database dan media

Menyalin volume Docker saat PostgreSQL masih berjalan menghasilkan cadangan yang mungkin tidak dapat dipulihkan. Paperless menyediakan exporter sendiri yang menulis dokumen beserta manifest JSON berisi semua metadata ke dalam bind mount ./export:

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

--delete menghapus file hasil ekspor yang tidak lagi cocok dengan dokumen saat ini, sehingga folder tersebut tetap menjadi mirror dan tidak terus membesar. --no-progress-bar menjaga output tetap bersih saat proses ini dijalankan dari cron.

Pemulihan dilakukan dengan document_importer pada folder yang sama di stack baru. Artinya, hanya direktori ekspor yang perlu Anda simpan dengan aman. Kirim direktori tersebut ke lokasi di luar server secara terjadwal menggunakan cadangan restic terenkripsi dengan deduplikasi dari VPS, dan jalankan ekspor terlebih dahulu agar restic tidak pernah menangkap arsip yang penulisannya belum selesai.

Verifikasi backup dengan memeriksa bahwa export/manifest.json tersedia dan jumlah file sesuai dengan jumlah dokumen pada antarmuka. Backup yang belum pernah Anda daftarkan bukanlah backup. Ekspor setiap malam yang mulai gagal tanpa diketahui bahkan lebih berisiko. Karena itu, minta cron job mengirimkan status keluarnya ke ntfy server milik Anda sendiri. Dengan demikian, Anda akan mengetahui kegagalan tersebut pada minggu saat kegagalan terjadi, bukan pada hari ketika Anda perlu melakukan pemulihan.

FAQ

Mengapa setiap halaman mengembalikan "Bad Request (400)" setelah saya mengarahkan domain ke sana?

Django menolak header Host karena domain Anda tidak tercantum dalam ALLOWED_HOSTS. Tetapkan PAPERLESS_URL=https://paperless.example.com di docker-compose.env, tanpa garis miring penutup, lalu jalankan docker compose up -d untuk membuat ulang container. Mengedit file env saja tidak berpengaruh karena container yang sedang berjalan tetap menggunakan environment saat container tersebut dimulai.

Saya menaruh PDF di folder consume, tetapi tidak terjadi apa pun. Apa masalahnya?

Periksa docker compose logs webserver terlebih dahulu. Error izin berarti USERMAP_UID dan USERMAP_GID tidak cocok dengan akun pemilik file, jadi perbaiki keduanya lalu buat ulang container. Jika tidak ada baris log sama sekali, berarti event file tidak pernah diterima. Hal ini terjadi pada network share karena notifikasi kernel tidak melewati network share tersebut. Tetapkan PAPERLESS_CONSUMER_POLLING_INTERVAL ke nilai seperti 30, lalu paperless akan memindai folder setiap 30 detik.

Dapatkah saya menjalankan paperless-ngx dengan SQLite sebagai pengganti PostgreSQL?

Ya, docker-compose.sqlite.yml didukung dan menggunakan lebih sedikit memori, sehingga sesuai untuk VPS kecil. Konsekuensinya terlihat ketika arsip bertambah besar: pencarian full-text dan pengeditan tag secara massal melambat secara nyata saat jumlah dokumen mencapai ribuan. Migrasi pada tahap berikutnya memerlukan export dan import, jadi pilih PostgreSQL sekarang jika Anda memperkirakan arsip akan terus bertambah.

Berapa banyak ruang disk yang sebenarnya diperlukan arsip hasil pemindaian?

Kira-kira dua kali ukuran file sumber. Paperless mempertahankan file asli tanpa perubahan dan menyimpan PDF kedua yang telah diproses dengan OCR serta memiliki lapisan teks yang dapat dicari, ditambah thumbnail berukuran kecil. Hasil pemindaian teks saja berukuran 200 KB tetap kecil. Hasil pemindaian berwarna berukuran 30 MB untuk kontrak panjang akan menggunakan sekitar 60 MB. Tambahkan direktori export jika Anda menyimpannya pada disk yang sama. Dengan demikian, arsip yang sama akan menggunakan ruang disk tiga kali lipat.

Apakah saya memerlukan container Tika dan Gotenberg?

Hanya jika Anda ingin file Word, Excel, atau OpenDocument diindeks bersama PDF. Keduanya mengonversi format tersebut ke PDF agar paperless dapat memprosesnya dengan OCR dan melakukan pencarian. Keduanya juga menambah 2 container yang berjalan dan beberapa ratus megabyte memori. Jadi, jangan gunakan keduanya pada mesin kecil jika semua file yang Anda arsipkan sudah berupa PDF atau gambar.

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