SSD Nodes Learn RAM 8GB — $66/ปี
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-01

ติดตั้ง Paperless-ngx บน VPS ด้วย Docker Compose

คู่มือติดตั้ง Paperless-ngx บน VPS ด้วย Docker Compose ครอบคลุม Postgres stack อย่างเป็นทางการ, PAPERLESS_URL, consume folder, ภาษา OCR, HTTPS และการสำรองข้อมูล

สิ่งที่คุณกำลังสร้าง

Paperless-ngx บน VPS จะเปลี่ยนโฟลเดอร์เอกสารกระดาษที่สแกนแล้วให้เป็นคลังเอกสารที่ค้นหาได้ คุณเพียงวาง PDF ไว้ในไดเรกทอรีที่เฝ้าดูอยู่ จากนั้นเซิร์ฟเวอร์จะเรียกใช้ OCR (การรู้จำอักขระด้วยแสง) เพื่อประมวลผลเอกสาร แยกข้อความออกมา คาดเดาวันที่และผู้ติดต่อ แล้วจัดเก็บเอกสารให้ Install นี้ใช้ไฟล์ Docker Compose เพียงไฟล์เดียวและมี 4 services หลังจากนั้นทั้งหมดเป็นการกำหนดค่า และคู่มือนี้จึงเน้นเนื้อหาส่วนดังกล่าวเป็นหลัก เพราะเป็นจุดที่การติดตั้งมักล้มเหลว

Paperless-ngx เป็น community fork ที่มีการดูแลต่อเนื่องของโครงการ Paperless ดั้งเดิม ซอฟต์แวร์นี้ใช้งานได้ฟรี ติดตั้งและดูแลด้วยตนเอง และจัดเก็บเอกสารของคุณเป็นไฟล์ปกติบนดิสก์ คุณจึงไม่ถูกปิดกั้นจากคลังเอกสารของตนเอง การเรียกใช้บน VPS แทนเครื่องภายในบ้านทำให้เข้าถึงเอกสารที่สแกนได้จากทุกที่ โดยไม่ต้องเปิด port บนเราเตอร์ที่บ้าน และทำงานร่วมกับ อินสแตนซ์ Nextcloud ส่วนตัวสำหรับไฟล์ที่ไม่ใช่เอกสารกระดาษ ได้เป็นอย่างดี.

สแตกทำงานอะไรจริง

ไฟล์ compose อย่างเป็นทางการจะเริ่มต้นคอนเทนเนอร์ 4 รายการ การทราบหน้าที่ของแต่ละรายการช่วยให้อ่าน log ได้ง่ายขึ้น

  • webserver: อิมเมจ paperless-ngx เอง ทำหน้าที่เรียกใช้เว็บอินเทอร์เฟซ API, consumer ที่ตรวจสอบโฟลเดอร์นำเข้าของคุณ และ worker งาน Celery ที่ทำ OCR
  • db: PostgreSQL ใช้จัดเก็บข้อมูลเมทาดาทา แท็ก ผู้ติดต่อ และตารางดัชนีสำหรับการค้นหาข้อความแบบเต็ม ไม่ได้ใช้จัดเก็บไฟล์ PDF ของคุณ
  • broker: Valkey ซึ่งเป็นที่จัดเก็บคีย์-ค่าแบบเข้ากันได้กับ Redis ใช้เป็นคิวงานระหว่างโพรเซสเว็บกับ worker
  • gotenberg และ tika: เป็นตัวเลือก และมีเฉพาะในรูปแบบ compose ของ -tika เท่านั้น โดยจะแปลงเอกสาร Office (.docx, .xlsx, .odt) เป็น PDF เพื่อให้ paperless จัดทำดัชนีเอกสารได้

ณ เดือน July 2026 ไฟล์ compose ของ postgres จะกำหนดเวอร์ชัน docker.io/library/postgres:18 และ docker.io/valkey/valkey:9-alpine ไว้ตายตัว และดึงแอปจาก ghcr.io/paperless-ngx/paperless-ngx:latest

ข้อกำหนดเบื้องต้น

  • KVM VPS ที่ใช้ Ubuntu 24.04 และมีสิทธิ์ sudo พร้อมติดตั้ง Docker และปลั๊กอิน Compose ไว้แล้ว หากยังไม่คุ้นเคยกับส่วนนี้ ให้เริ่มจาก พื้นฐาน Docker Compose สำหรับ VPS แล้วกลับมาที่นี่
  • ชื่อโดเมนที่มีระเบียน A ชี้ไปยัง VPS Paperless จะไม่ให้บริการบน hostname ที่ยังไม่ได้กำหนดไว้ จึงควรเตรียมส่วนนี้ให้เรียบร้อยตั้งแต่ต้น
  • หน่วยความจำเป็นข้อจำกัดหลัก PostgreSQL, Valkey, gunicorn และ worker ของ Tesseract OCR ที่ทำงานพร้อมกัน ใช้หน่วยความจำ 2 GB ได้สำหรับการใช้งานเล็กน้อย ควรจัดสรร 4 GB หากวางแผนนำเข้าสแกนหลายร้อยรายการที่ค้างอยู่ เพราะการทำ OCR กับ PDF หลายหน้าขนาดใหญ่ทำให้หน่วยความจำพุ่งสูง และ kernel อาจยุติ worker ด้วย out-of-memory killer
  • พื้นที่ดิสก์: ระบบจัดเก็บเอกสารเก็บถาวรไว้ 2 ชุด ได้แก่ไฟล์ต้นฉบับและไฟล์ PDF เก็บถาวรที่ผ่าน OCR แล้ว ดังนั้นควรเผื่อพื้นที่ประมาณ 2 เท่าของขนาดไฟล์สแกน

รับไฟล์ compose อย่างเป็นทางการ

มีตัวติดตั้งแบบโต้ตอบ:

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

ตัวติดตั้งจะถามคำถามและเขียนไฟล์ให้คุณ การทำด้วยตนเองใช้ 4 คำสั่ง และช่วยให้คุณทราบว่าไฟล์ทั้งหมดอยู่ที่ใด ซึ่งเป็นสิ่งที่จำเป็นสำหรับเซิร์ฟเวอร์ที่คุณต้องดูแลต่อไป

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 มี 1 บรรทัด คือ COMPOSE_PROJECT_NAME=paperless ชื่อนี้จะกลายเป็นคำนำหน้าของทุก container และ volume ดังนั้นอย่าลบชื่อนี้แล้วสงสัยว่าเหตุใด docker compose down -v จึงค้นหาข้อมูลของคุณไม่พบ

กำหนดค่า docker-compose.env ก่อนเริ่มต้นครั้งแรก

มีการตั้งค่า 2 รายการที่ไม่สามารถเว้นว่างได้ ให้สร้างคีย์ลับด้วยคำสั่งที่โครงการระบุไว้:

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 ซึ่งเป็นค่าตามตัวอักษร ค่านี้ใช้ลงลายมือชื่อในคุกกี้เซสชัน หากปล่อยไว้ ผู้ใดก็ตามที่ทราบค่าเริ่มต้นก็สามารถปลอมแปลงเซสชันได้ ให้กำหนดค่าก่อนเริ่มต้นครั้งแรก เนื่องจากการเปลี่ยนค่าภายหลังจะทำให้ผู้ใช้ทุกคนออกจากระบบ

PAPERLESS_URL คือการตั้งค่าที่ช่วยประหยัดเวลาได้มากที่สุด Paperless เป็นแอปพลิเคชัน Django และ Django จะตรวจสอบส่วนหัว Host ของทุกคำขอ กำหนดค่า PAPERLESS_URL แล้วระบบจะเติม ALLOWED_HOSTS, CORS_ALLOWED_HOSTS และ CSRF_TRUSTED_ORIGINS ให้โดยอัตโนมัติ หากปล่อยว่าง ชี้โดเมนมายังเครื่อง และทุกหน้าส่งคืน Bad Request (400) พร้อม DisallowedHost ในบันทึกของคอนเทนเนอร์ ให้เขียนค่าโดยไม่มีเครื่องหมายทับต่อท้ายและไม่มีพาธ

USERMAP_UID และ USERMAP_GID กำหนดผู้ใช้ที่คอนเทนเนอร์ใช้ทำงาน ให้ตรงกับบัญชีของคุณเอง โดยตรวจสอบด้วย id -u และ id -g หากค่าไม่ตรงกัน ไฟล์ที่คุณคัดลอกไปยังโฟลเดอร์ consume จะไม่สามารถอ่านได้โดย consumer และบันทึกจะแสดงข้อผิดพลาดด้านสิทธิ์แทนการนำเข้า

เริ่มต้น stack และสร้างผู้ใช้รายแรก

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

createsuperuser จะแจ้งให้ป้อนชื่อผู้ใช้ อีเมล และรหัสผ่าน ระบบไม่มีข้อมูลเข้าสู่ระบบเริ่มต้น ดังนั้นหากข้ามขั้นตอนนี้ คุณจะพบหน้าลงชื่อเข้าใช้ที่ไม่ยอมรับข้อมูลใด ๆ รอรายการบันทึกที่รายงานว่าเซิร์ฟเวอร์กำลังรับฟังบนพอร์ต 8000 ก่อนเปิดเบราว์เซอร์ การเริ่มต้นครั้งแรกจะเรียกใช้การย้ายฐานข้อมูลด้วย ซึ่งใช้เวลาประมาณ 1 ถึง 2 นาที

ตรวจสอบระบบภายในเครื่องก่อนเชื่อมต่อโดเมน:

curl -I http://127.0.0.1:8000

การเปลี่ยนเส้นทางจาก 302 ไปยัง /accounts/login/ หมายความว่า stack ทำงานเป็นปกติ

วาง HTTPS ไว้ด้านหน้า

ไฟล์ compose มาตรฐานเผยแพร่ 8000:8000 ซึ่งผูกกับทุกอินเทอร์เฟซ บน VPS สาธารณะ การตั้งค่านี้จะให้บริการคลังเอกสารทั้งหมดของคุณผ่าน HTTP แบบไม่เข้ารหัสแก่ผู้ที่พบที่อยู่ดังกล่าว ให้เปลี่ยนบรรทัดพอร์ตเพื่อผูกกับ loopback เท่านั้น:

    ports:
      - "127.0.0.1:8000:8000"

จากนั้นให้ reverse proxy จัดการ TLS (ความปลอดภัยของชั้นการส่งข้อมูล) และส่งต่อไปยัง 127.0.0.1:8000 หากนี่เป็นแอปเดียวบนเครื่อง คุณสามารถใช้ proxy ใดก็ได้ที่มีไคลเอ็นต์ ACME (สภาพแวดล้อมการจัดการใบรับรองอัตโนมัติ) หากคุณกำลังเรียกใช้คอนเทนเนอร์หลายรายการภายใต้การตั้งค่าใบรับรองเดียว ให้ทำตาม รูปแบบ reverse proxy ของ Traefik สำหรับแอป Docker Compose หลายรายการ และเชื่อมต่อบริการ webserver เข้ากับเครือข่ายของ proxy โดยไม่เผยแพร่พอร์ตเลย

ไม่ว่าคุณจะใช้ proxy ใด proxy นั้นต้องส่ง X-Forwarded-Proto: https หากไม่มีส่วนนี้ Django จะเข้าใจว่าคำขอมาถึงผ่าน HTTP การตรวจสอบต้นทางของแบบฟอร์มเข้าสู่ระบบจะล้มเหลว และคุณจะได้รับ CSRF verification failed. Request aborted. บนหน้าที่แสดงผลถูกต้อง อีกส่วนหนึ่งของการแก้ไขนี้คือการกำหนด PAPERLESS_URL ให้เป็นที่อยู่ https:// ที่คุณพิมพ์ในเบราว์เซอร์ทุกประการ

นอกจากนี้ ให้เพิ่มขีดจำกัดขนาดการอัปโหลดของ proxy ด้วย ไฟล์สแกนขนาด 40 MB ที่ส่งผ่าน proxy ซึ่งจำกัดขนาดเนื้อหาไว้ที่ 1 MB จะถูกปฏิเสธก่อนที่ paperless จะได้รับไฟล์ และเบราว์เซอร์จะแสดงข้อผิดพลาดการอัปโหลดทั่วไป

การทำงานของไดเรกทอรี consume

ไฟล์ compose จะ bind-mount ./consume จากไดเรกทอรี compose เข้าไปในคอนเทนเนอร์ ไฟล์ใดก็ตามที่คุณวางไว้ที่นั่นจะถูกนำเข้า แล้วลบออกจากโฟลเดอร์ เนื่องจากไฟล์ดังกล่าวถูกจัดเก็บอยู่ใน media volume ภายใต้การจัดการของ paperless แล้ว

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

คุณควรเห็น consumer รับชื่อไฟล์ เรียกใช้ OCR และทำงานเสร็จโดยแสดงบรรทัดที่ระบุว่าเพิ่มเอกสารแล้ว กระบวนการทั้งหมดใช้เวลาไม่กี่วินาทีสำหรับเอกสารสแกน 1 หน้า และอาจใช้เวลา 1 นาทีขึ้นไปสำหรับเอกสารที่มีหลายหน้า

การตั้งค่า 2 รายการจะเปลี่ยนวิธีค้นหาไฟล์ PAPERLESS_CONSUMER_RECURSIVE=true ทำให้ paperless ค้นหาในโฟลเดอร์ย่อย และ PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true จะเปลี่ยนชื่อโฟลเดอร์ย่อยแต่ละรายการให้เป็นแท็ก ดังนั้นเมื่อนำไฟล์ไปวางใน consume/invoices/2026/ ระบบจะแท็กไฟล์นั้นด้วย invoices และ 2026 นี่คือระบบจัดเก็บเอกสารที่มีค่าใช้จ่ายต่ำที่สุดที่คุณจะสร้างได้

การตรวจจับไฟล์เป็นอีกส่วนหนึ่ง โดยค่าเริ่มต้น PAPERLESS_CONSUMER_POLLING_INTERVAL คือ 0 ซึ่งหมายความว่า paperless ใช้การแจ้งเตือนระบบไฟล์จาก kernel และการแจ้งเตือนจะเกิดขึ้นทันที การแจ้งเตือนเหล่านี้ไม่สามารถข้ามผ่านระบบไฟล์เครือข่ายได้ หากโฟลเดอร์ consume ของคุณเป็น NFS หรือ SMB share เพื่อให้ network scanner เขียนไฟล์ลงไป ระบบจะตรวจไม่พบไฟล์ใดๆ และวิธีแก้คือกำหนดช่วงเวลาเป็นจำนวนวินาทีที่มากกว่า 0 เพื่อให้ paperless สแกนโฟลเดอร์แทน

ภาษา OCR และทรัพยากรที่ต้องใช้

PAPERLESS_OCR_LANGUAGE รับรหัส Tesseract แบบสามตัวอักษร โดยค่าเริ่มต้นคือ eng หากต้องการใช้หลายภาษา ให้รวมรหัสด้วยเครื่องหมายบวก เช่น deu+eng จากนั้น Tesseract จะประมวลผลทุกภาษาและเก็บผลลัพธ์ที่ดีที่สุด ดังนั้นภาษาแต่ละรายการที่เพิ่มจะเพิ่มเวลา CPU ที่ใช้กับทุกหน้าเป็นทวีคูณ บน VPS ที่ใช้ vCPU ร่วมกัน ความแตกต่างอาจเป็นระหว่างการสแกนที่เสร็จภายใน 10 วินาที กับ 1 นาที ให้ระบุเฉพาะภาษาที่ใช้เขียนเอกสารจริงเท่านั้น

อิมเมจนี้มีภาษาอังกฤษ เยอรมัน อิตาลี สเปน และฝรั่งเศส หากต้องการใช้ภาษาอื่น ให้เพิ่มภาษาใน PAPERLESS_OCR_LANGUAGES โดยคั่นรายการด้วยช่องว่าง เช่น PAPERLESS_OCR_LANGUAGES=tur ces แล้ว restart คอนเทนเนอร์จะดาวน์โหลดแพ็กข้อมูล Tesseract เมื่อเริ่มต้นระบบ ดังนั้นการบูตครั้งแรกหลังจากเปลี่ยนแปลงค่านี้จะใช้เวลานานขึ้น

สำรองข้อมูลฐานข้อมูลและไฟล์มีเดีย

การคัดลอก Docker volumes ขณะที่ PostgreSQL กำลังทำงาน อาจทำให้ได้ข้อมูลสำรองที่ไม่สามารถกู้คืนได้ Paperless มี exporter ของตัวเอง ซึ่งเขียนเอกสารพร้อมไฟล์ manifest รูปแบบ JSON ที่มีข้อมูลเมทาดาทาทั้งหมดลงใน ./export bind mount:

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

--delete จะลบไฟล์ที่ส่งออกแล้วซึ่งไม่ตรงกับเอกสารปัจจุบันอีกต่อไป เพื่อให้โฟลเดอร์เป็นสำเนาที่ตรงกันแทนที่จะขยายขึ้นเรื่อย ๆ --no-progress-bar จะทำให้ผลลัพธ์สะอาดเมื่อคำสั่งนี้ทำงานจาก cron

การกู้คืนคือ document_importer โดยใช้โฟลเดอร์เดียวกันนั้นกับ stack ใหม่ ดังนั้นสิ่งเดียวที่คุณต้องเก็บรักษาให้ปลอดภัยคือไดเรกทอรีส่งออก ส่งไดเรกทอรีนี้ไปยังตำแหน่งนอกระบบตามกำหนดเวลาด้วย restic backups ที่เข้ารหัสและตัดข้อมูลซ้ำจาก VPS และเรียกใช้การส่งออกก่อน เพื่อไม่ให้ restic บันทึกไฟล์เก็บถาวรที่เขียนไม่เสร็จ

ตรวจสอบข้อมูลสำรองโดยตรวจว่า export/manifest.json มีอยู่ และจำนวนไฟล์ตรงกับจำนวนเอกสารในอินเทอร์เฟซ ข้อมูลสำรองที่คุณไม่เคยแสดงรายการไม่ใช่ข้อมูลสำรองที่ใช้งานได้

FAQ

เหตุใดทุกหน้าจึงแสดง "Bad Request (400)" หลังจากชี้โดเมนมายังระบบ

Django ปฏิเสธส่วนหัว Host เนื่องจากโดเมนของคุณไม่ได้อยู่ใน ALLOWED_HOSTS กำหนดค่า PAPERLESS_URL=https://paperless.example.com ใน docker-compose.env โดยไม่ใส่เครื่องหมายทับต่อท้าย จากนั้นเรียกใช้ docker compose up -d เพื่อสร้าง container ใหม่ การแก้ไขไฟล์ env เพียงอย่างเดียวไม่มีผล เพราะ container ที่กำลังทำงานใช้ environment ที่ได้รับเมื่อเริ่มทำงาน

ฉันวางไฟล์ PDF ในโฟลเดอร์ consume แล้วไม่มีอะไรเกิดขึ้น ต้องแก้ไขอย่างไร

ตรวจสอบ docker compose logs webserver ก่อน ข้อผิดพลาดด้านสิทธิ์หมายความว่า USERMAP_UID และ USERMAP_GID ไม่ตรงกับ account ที่เป็นเจ้าของไฟล์ ให้แก้ไขค่าเหล่านั้นแล้วสร้าง container ใหม่ หากไม่มี log ปรากฏเลย แสดงว่า file event ไม่มาถึงระบบ ซึ่งเกิดขึ้นกับ network share เพราะ kernel notification ไม่สามารถข้ามไปยัง network share ได้ กำหนดค่า PAPERLESS_CONSUMER_POLLING_INTERVAL เป็นค่าประมาณ 30 แล้ว paperless จะสแกนโฟลเดอร์ทุก 30 วินาทีแทน

สามารถใช้งาน paperless-ngx กับ SQLite แทน PostgreSQL ได้หรือไม่

ได้ รองรับ docker-compose.sqlite.yml และใช้ memory น้อยกว่า จึงเหมาะกับ VPS ขนาดเล็ก ข้อแลกเปลี่ยนจะเห็นได้ชัดเมื่อ archive มีขนาดใหญ่ขึ้น: full-text search และการแก้ไข tag แบบกลุ่มจะช้าลงอย่างเห็นได้ชัดเมื่อมีเอกสารหลักพันรายการ การย้ายระบบในภายหลังต้อง export และ import ดังนั้นให้เลือก PostgreSQL ตั้งแต่ตอนนี้ หากคาดว่า archive จะเพิ่มขึ้นต่อเนื่อง

Archive ของเอกสารสแกนต้องใช้ disk เท่าใด

โดยประมาณ 2 เท่าของขนาดไฟล์ต้นฉบับ Paperless จะเก็บต้นฉบับไว้โดยไม่แก้ไข และจัดเก็บ PDF ที่ผ่าน OCR อีกชุดพร้อม text layer ที่ค้นหาได้ รวมถึง thumbnail ขนาดเล็ก ไฟล์สแกนแบบมีแต่ข้อความขนาด 200 KB จะยังมีขนาดเล็ก ส่วนไฟล์สแกนสีของสัญญาขนาดยาว 30 MB จะใช้พื้นที่ประมาณ 60 MB หากเก็บ directory สำหรับ export ไว้บน disk เดียวกัน archive เดียวกันจะใช้พื้นที่บน disk รวม 3 เท่า

จำเป็นต้องใช้ container ของ Tika และ Gotenberg หรือไม่

ใช้เฉพาะกรณีที่ต้องการให้ระบบ index ไฟล์ Word, Excel หรือ OpenDocument ร่วมกับไฟล์ PDF ทั้งสองระบบจะแปลงรูปแบบเหล่านั้นเป็น PDF เพื่อให้ paperless ทำ OCR และค้นหาได้ นอกจากนี้ยังเพิ่ม container ที่ทำงานอยู่อีก 2 รายการและใช้ memory เพิ่มอีกหลายร้อยเมกะไบต์ ดังนั้นให้ข้ามระบบเหล่านี้บนเครื่องขนาดเล็ก หากไฟล์ทั้งหมดที่จัดเก็บเป็น PDF หรือ image อยู่แล้ว

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