VPS'te Paperless-ngx Kurulumu ve Docker Compose
VPS üzerinde Paperless-ngx kurulumunu Docker Compose ile yapın. Postgres yığını, PAPERLESS_URL, consume klasörü, OCR dilleri, HTTPS ve yedekleme açıklanır.
Oluşturulan sistem
Bir VPS üzerinde Paperless-ngx, taranmış belgelerin bulunduğu bir klasörü aranabilir bir arşive dönüştürür. İzlenen bir dizine PDF bırakıldığında sunucu üzerinde OCR (optik karakter tanıma) çalıştırılır, metin çıkarılır, tarih ve yazışılan kişi tahmin edilir ve belge arşivlenir. Kurulum, dört hizmet içeren tek bir Docker Compose dosyasından oluşur. Bundan sonraki işlemler yapılandırmadır. Bu kılavuzun büyük bölümü buna ayrılmıştır, çünkü kurulumlar çoğunlukla bu aşamada başarısız olur.
Paperless-ngx, özgün Paperless projesinin topluluk tarafından sürdürülen çatallanmış sürümüdür. Ücretsizdir, kendi sunucunuzda barındırılır ve belgelerinizi diskte düz dosyalar olarak depolar. Bu nedenle kendi arşivinize erişiminizi hiçbir zaman kaybetmezsiniz. Bir VPS üzerinde çalıştırılması, ev yönlendiricinizde port açmadan taramalara her yerden erişilmesini sağlar. Ayrıca, kağıt olmayan dosyalar için özel bir Nextcloud örneğiyle birlikte kullanıma uygundur.
Yığının gerçekte çalıştırdığı bileşenler
Resmî compose dosyası dört container başlatır. Her birinin ne yaptığını bilmek, logları anlaşılır hâle getirir.
webserver: paperless-ngx imajının kendisidir. Web arayüzünü, API'yi, input klasörünü izleyen consumer'ı ve OCR işlemlerini gerçekleştiren Celery task worker'larını çalıştırır.db: PostgreSQL'dir. Metadata'yı, etiketleri, ilgili kişileri ve tam metin arama dizini tablolarını tutar. PDF dosyalarınızı tutmaz.broker: Redis uyumlu bir key-value store olan Valkey'dir. Web process'i ile worker'lar arasındaki task queue'dur.gotenbergvetika: yalnızca-tikacompose varyantlarında kullanılan isteğe bağlı bileşenlerdir. Office belgelerini (.docx,.xlsx,.odt) PDF'ye dönüştürerek paperless'ın bunları dizine eklemesini sağlarlar.
Temmuz 2026 itibarıyla postgres compose dosyası docker.io/library/postgres:18 ve docker.io/valkey/valkey:9-alpine sürümlerini sabitler ve uygulamayı ghcr.io/paperless-ngx/paperless-ngx:latest üzerinden çeker.
Önkoşullar
- sudo erişimine sahip bir Ubuntu 24.04 KVM VPS ve Compose eklentisi zaten kurulmuş Docker. Bu kısım yeniyse VPS için Docker Compose temelleri ile başlayıp buraya dönülmelidir.
- VPS'ye yönlenen bir A kaydına sahip alan adı. Paperless, kendisine bildirilmemiş bir ana bilgisayar adı üzerinden hizmet sunmayı reddeder. Bu nedenle bu gereksinim beklenenden daha erken karşılanmalıdır.
- Gerçek kısıt bellek kapasitesidir. PostgreSQL, Valkey, gunicorn ve bir Tesseract OCR çalışanı aynı anda bellekte bulunduğunda, düşük yoğunluklu kullanım için 2 GB yeterlidir. Yüzlerce taramadan oluşan birikmiş belgeleri içe aktarmayı planlıyorsanız 4 GB verilmelidir. Büyük, çok sayfalı bir PDF üzerinde OCR çalıştırılması, çekirdeğin bellek yetersizliği sonlandırıcısının bir çalışanı sonlandırmasına neden olan bellek artışıdır.
- Disk: Arşiv iki kez depolanır: özgün dosya ve OCR uygulanmış arşiv PDF'si. Bu nedenle taramalarınızın toplam boyutunun yaklaşık iki katı kadar alan ayrılmalıdır.
Resmi compose dosyalarını alın
Etkileşimli bir yükleyici bulunur:
bash -c "$(curl --location --silent --show-error https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"Sorular sorar ve dosyaları sizin için yazar. Bunu elle yapmak dört komut gerektirir ve her şeyin nerede olduğunu bilmenizi sağlar. Bu, sürdüreceğiniz bir sunucuda istenen yaklaşımdır.
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/.envVaryantlar aynı dizinde bulunur: docker-compose.sqlite.yml, docker-compose.mariadb.yml ve her birinin -tika sürümü. Yeni bir kurulum için postgres seçilmelidir. SQLite birkaç yüz belge için yeterlidir, ancak tam metin arama dizini PostgreSQL'e kıyasla çok daha önce yavaşlar.
.env dosyası COMPOSE_PROJECT_NAME=paperless satırını içerir. Bu ad, her container ve volume için ön ek olur. Bu nedenle dosyayı silip ardından docker compose down -v komutunun verilerinizi neden bulamadığını araştırmayın.
İlk başlatmadan önce docker-compose.env dosyasını yapılandırma
İki ayar isteğe bağlı değildir. Gizli anahtarı, projenin belgelediği komutla oluşturun:
python3 -c "import secrets; print(secrets.token_urlsafe(64))"Ardından docker-compose.env dosyasını düzenleyin:
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=1000PAPERLESS_SECRET_KEY, varsayılan olarak change-me değişmez değeriyle gelir. Oturum çerezlerini imzalar. Bu nedenle değiştirilmeden bırakılırsa varsayılan değeri bilen herkes sahte bir oturum oluşturabilir. İlk başlatmadan önce ayarlayın. Daha sonra değiştirilmesi tüm kullanıcıların oturumunu kapatır.
PAPERLESS_URL size bir saat kazandıran ayardır. Paperless bir Django uygulamasıdır ve Django her isteğin Host üstbilgisini doğrular. PAPERLESS_URL değerini ayarladığınızda ALLOWED_HOSTS, CORS_ALLOWED_HOSTS ve CSRF_TRUSTED_ORIGINS değerlerini sizin için doldurur. Alanı boş bırakıp bir etki alanını sunucuya yönlendirirseniz her sayfa Bad Request (400) döndürür ve kapsayıcı günlüğünde DisallowedHost görünür. Değeri, sonda eğik çizgi veya yol olmayacak şekilde yazın.
USERMAP_UID ve USERMAP_GID, kapsayıcının hangi kullanıcı olarak çalışacağını belirler. Bunları id -u ve id -g ile kontrol edilen kendi hesabınızla eşleştirin. Eşleşmezlerse consume klasörüne kopyaladığınız dosyalar consumer tarafından okunamaz. Günlükte içe aktarma yerine izin hatası görünür.
Yığını başlatma ve ilk kullanıcıyı oluşturma
docker compose pull
docker compose up -d
docker compose run --rm webserver createsuperuser
docker compose logs -f webservercreatesuperuser bir kullanıcı adı, e-posta adresi ve parola ister. Varsayılan oturum açma bilgileri yoktur. Bu adım atlanırsa hiçbir bilgiyi kabul etmeyen bir oturum açma sayfasıyla karşılaşılır. Tarayıcıyı açmadan önce sunucunun 8000 portunu dinlediğini bildiren günlük satırını bekleyin. İlk başlatma sırasında veritabanı geçişleri de çalıştırılır. Bu işlem bir veya iki dakika sürer.
Bir alan adını kullanmadan önce hizmeti yerel olarak kontrol edin:
curl -I http://127.0.0.1:8000/accounts/login/ adresine yapılan 302 yönlendirmesi, yığının sağlıklı olduğunu gösterir.
Önüne HTTPS koyma
Standart compose dosyası, her arabirime bağlanan 8000:8000 bağlantı noktasını yayımlar. Genel erişime açık bir VPS üzerinde bu durum, adresi bulan herkesin tüm belge arşivinize düz HTTP üzerinden erişebilmesine neden olur. Bağlantı noktası satırı yalnızca loopback'e bağlanacak şekilde değiştirilmelidir:
ports:
- "127.0.0.1:8000:8000"Ardından TLS'yi (transport layer security) bir reverse proxy'de sonlandırın ve istekleri 127.0.0.1:8000 adresine yönlendirin. Sunucudaki tek uygulama buysa ACME (automatic certificate management environment) istemcisine sahip herhangi bir proxy kullanılabilir. Tek bir sertifika yapılandırmasının arkasında birden çok container çalıştırıyorsanız birden çok Docker Compose uygulaması için Traefik reverse proxy modelini izleyin ve webserver hizmetini hiç yayımlanmış bağlantı noktası olmadan proxy ağına bağlayın.
Kullanılan proxy ne olursa olsun X-Forwarded-Proto: https göndermelidir. Bu başlık gönderilmezse Django isteğin HTTP üzerinden geldiğini düşünür, oturum açma formundaki origin denetimi başarısız olur ve doğru görünen bir sayfada CSRF verification failed. Request aborted. hatası alınır. Bu düzeltmenin diğer kısmı, PAPERLESS_URL değerinin tarayıcıya yazılan tam https:// adresine ayarlanmasıdır.
Ayrıca proxy'nin yükleme boyutu sınırını artırın. 1 MB ile sınırlanan bir proxy üzerinden gönderilen 40 MB boyutundaki tarama, paperless isteği hiç görmeden önce reddedilir ve tarayıcı genel bir yükleme hatası bildirir.
consume dizininin çalışma şekli
compose dosyası, ./consume yolunu compose dizininden container içine bind mount eder. Bu dizine yerleştirilen her şey içe aktarılır ve ardından klasörden silinir. Bunun nedeni, dosyanın artık paperless yönetimindeki media volume içinde bulunmasıdır.
cp ~/scan-2026-07-14.pdf ~/paperless/consume/
docker compose logs -f webserverConsumer'ın dosya adını alması, OCR çalıştırması ve belgenin eklendiğini bildiren bir satırla işlemi tamamlaması beklenir. Tek sayfalık bir tarama için tüm işlem birkaç saniye sürer. Uzun belgelerde bu süre 1 dakika veya daha fazla olabilir.
Dosyaların nasıl bulunduğunu iki ayar değiştirir. PAPERLESS_CONSUMER_RECURSIVE=true, paperless'ın alt klasörleri de aramasını sağlar. PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true ise her alt klasör adını bir tag'e dönüştürür. Böylece bir dosyanın consume/invoices/2026/ içine bırakılması, dosyaya invoices ve 2026 tag'lerinin eklenmesini sağlar. Bu, kurulabilecek en düşük maliyetli dosyalama sistemidir.
Algılama bunun diğer kısmıdır. Varsayılan olarak PAPERLESS_CONSUMER_POLLING_INTERVAL değeri 0 şeklindedir. Bu, paperless'ın hemen tetiklenen kernel dosya sistemi bildirimlerini kullandığı anlamına gelir. Bu bildirimler network filesystem üzerinden iletilmez. consume klasörü, network scanner'ın dosya yazabilmesi için NFS veya SMB paylaşımıysa hiçbir dosya algılanmaz. Çözüm, aralığı pozitif bir saniye değerine ayarlamaktır. Böylece paperless bunun yerine klasörü tarar.
OCR dilleri ve maliyetleri
PAPERLESS_OCR_LANGUAGE, varsayılan olarak eng olmak üzere üç harfli bir Tesseract kodu alır. Dilleri deu+eng örneğinde olduğu gibi artı işaretiyle birleştirin. Tesseract daha sonra her dili dener ve en iyi sonucu korur. Bu nedenle eklenen her dil, her sayfa için harcanan CPU süresini artırır. Paylaşımlı vCPU kullanan bir VPS'de bu, taramanın on saniyede tamamlanması ile bir dakikada tamamlanması arasındaki fark olabilir. Yalnızca belgelerinizin gerçekten yazıldığı dilleri listeleyin.
İmajda İngilizce, Almanca, İtalyanca, İspanyolca ve Fransızca bulunur. Diğer diller için dili PAPERLESS_OCR_LANGUAGES içine boşlukla ayrılmış bir liste olarak ekleyin; örneğin PAPERLESS_OCR_LANGUAGES=tur ces. Ardından yeniden başlatın. Container, Tesseract veri paketlerini başlangıçta indirir. Bu nedenle değişiklikten sonraki ilk açılış daha yavaş olur.
Veritabanını ve medyayı yedekleme
PostgreSQL çalışırken Docker volume'larını kopyalamak, geri yüklenemeyebilecek bir yedek oluşturur. Paperless, belgeleri ve tüm meta verilerin JSON bildirimini ./export bind mount'una yazan kendi dışa aktarma aracını sunar:
docker compose exec webserver document_exporter ../export --delete --no-progress-bar--delete, artık mevcut bir belgeyle eşleşmeyen dışa aktarılmış dosyaları kaldırır. Böylece klasör sürekli büyümek yerine bir ayna olarak kalır. --no-progress-bar, işlem cron'dan çalıştırıldığında çıktının temiz kalmasını sağlar.
Geri yükleme, yeni bir stack üzerinde aynı klasöre karşı document_importer gerçekleştirilir. Bu nedenle güvenliğini sağlamanız gereken tek şey dışa aktarma dizinidir. Bu dizini VPS'nizden şifrelenmiş ve tekilleştirilmiş restic yedekleriyle zamanlanmış olarak uzak konuma gönderin. Önce dışa aktarmayı çalıştırın; böylece restic hiçbir zaman kısmen yazılmış bir arşivi yakalamaz.
export/manifest.json dosyasının mevcut olduğunu ve dosya sayısının arayüzdeki belge sayınızla eşleştiğini kontrol ederek bir yedeği doğrulayın. Hiç listelemediğiniz bir yedek, yedek değildir.
FAQ
Alan adımı yönlendirdikten sonra neden her sayfa "Bad Request (400)" döndürüyor?
Django, alan adınız ALLOWED_HOSTS içinde olmadığı için Host üstbilgisini reddetti. Sondaki eğik çizgi olmadan PAPERLESS_URL=https://paperless.example.com değerini docker-compose.env içinde ayarlayın, ardından kapsayıcıyı yeniden oluşturmak için docker compose up -d komutunu çalıştırın. Ortam dosyasını tek başına düzenlemek işe yaramaz, çünkü çalışan kapsayıcı başlatıldığı sıradaki ortamı kullanmaya devam eder.
consume klasörüne bir PDF bıraktım ve hiçbir şey olmadı. Sorun nedir?
Önce docker compose logs webserver değerini kontrol edin. İzin hatası, USERMAP_UID ve USERMAP_GID değerlerinin dosyanın sahibi olan hesapla eşleşmediğini gösterir. Bu değerleri düzeltin ve kapsayıcıyı yeniden oluşturun. Günlükte hiç satır bulunmaması, dosya olayının ulaşmadığı anlamına gelir. Bu durum, çekirdek bildirimleri ağ paylaşımlarından geçmediği için oluşur. PAPERLESS_CONSUMER_POLLING_INTERVAL değerini 30 gibi bir değere ayarlayın. Böylece paperless klasörü bunun yerine her 30 saniyede bir tarar.
paperless-ngx, PostgreSQL yerine SQLite ile çalıştırılabilir mi?
Evet, docker-compose.sqlite.yml desteklenir ve daha az bellek kullanır. Bu nedenle küçük bir VPS için uygundur. Arşiv büyüdükçe fark ortaya çıkar: tam metin araması ve toplu etiket düzenlemeleri, belge sayısı binlere ulaştığında belirgin şekilde yavaşlar. Daha sonra geçiş yapmak için dışa aktarma ve içe aktarma işlemleri gerekir. Arşivin büyümeye devam etmesini bekliyorsanız şimdi PostgreSQL'i seçin.
Bir tarama arşivi gerçekte ne kadar disk alanı gerektirir?
Kaynak dosyaların boyutunun yaklaşık iki katı gerekir. Paperless, orijinali değiştirmeden saklar ve aranabilir metin katmanına sahip, OCR uygulanmış ikinci bir PDF ile küçük küçük resimler depolar. Yalnızca metin içeren 200 KB boyutunda bir tarama küçük kalır. Uzun bir sözleşmenin 30 MB boyutundaki renkli taraması yaklaşık 60 MB yer kaplar. Dışa aktarma dizinini aynı diskte tutuyorsanız bunu da hesaba katın. Bu durumda aynı arşiv diskte üç katı alan kaplar.
Tika ve Gotenberg kapsayıcılarına ihtiyacım var mı?
Yalnızca Word, Excel veya OpenDocument dosyalarının PDF'lerinizle birlikte dizine eklenmesini istiyorsanız gerekir. paperless'ın bu dosyalara OCR uygulayabilmesi ve arama yapabilmesi için bunları PDF'ye dönüştürürler. Ayrıca 2 kapsayıcının daha çalışmasını ve birkaç yüz megabayt bellek kullanılmasını gerektirirler. Arşivlediğiniz her şey zaten PDF veya görüntüyse küçük bir sistemde bunları kullanmayın.