SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-28

VPS Uzerinde Paperless-ngx Kurulumu ve Yapilandirma

Docker Compose ile VPS uzerinde Paperless-ngx kurulumunu ogrenin. Postgres stack, PAPERLESS_URL ayari, OCR dilleri, HTTPS yapilandirmasi ve veri yedekleme adimlarini inceleyin.

Ne inşa ediyorsunuz

Bir VPS üzerinde çalışan Paperless-ngx, taranmış kağıtlardan oluşan bir klasörü aranabilir bir arşive dönüştürür. Bir PDF dosyasını izlenen bir dizine bıraktığınızda, sunucu üzerinde OCR (optik karakter tanıma) çalıştırır, metni çıkarır, bir tarih ve gönderici tahmini yapar ve dosyayı arşivler. Kurulum, dört servisten oluşan tek bir Docker Compose dosyasıdır. Bundan sonraki her şey yapılandırmadır ve bu kılavuzun büyük bir kısmı buna ayrılmıştır, çünkü kurulumlar genellikle bu aşamada hata verir. Bu bir fotoğraf kütüphanesi değildir: OCR ve gönderici tahmini, tatil JPEG'lerinden oluşan bir klasör için hiçbir işe yaramaz; bu yüzden onları bunun için oluşturulmuş bir fotoğraf sunucusuna koyun ve paperless'ı kağıt belgeler için kullanın.

Paperless-ngx, özgün Paperless projesinin topluluk tarafından sürdürülen fork sürümüdür. Ücretsizdir, self-host edilebilir ve belgelerinizi diskte düz dosyalar olarak saklar. Böylece kendi arşivinize erişiminizi hiçbir zaman kaybetmezsiniz. Bir ev bilgisayarı yerine VPS üzerinde çalıştırıldığında taramalarınıza her yerden erişebilirsiniz. Bunun için ev yönlendiricinizde port açmanız gerekmez. Bu yapı, kağıt üzerinde olmayan dosyalar için özel bir Nextcloud instance'ı ile de iyi şekilde çalışır. Aynı yaklaşım, tarayıcınızın bağlı olduğu masaüstü bilgisayar için de geçerlidir. VPS üzerinde size ait bir RustDesk relay çalıştırarak bu bilgisayarı da yönlendiricide port açmadan başka bir yerden kullanabilirsiniz.

Yığının gerçekte ne çalıştırdığı

Resmi compose dosyası dört adet container başlatır; her birinin ne işe yaradığını bilmek, log kayıtlarını okunabilir kılar.

  • webserver: paperless-ngx imajının kendisidir. Web arayüzünü, API'yi, girdi klasörünüzü izleyen tüketiciyi ve OCR işlemlerini gerçekleştiren Celery görev çalışanlarını (workers) çalıştırır.
  • db: PostgreSQL. Meta verileri, etiketleri, yazışmaları ve tam metin arama dizin tablolarını tutar. PDF dosyalarınızı burada tutmaz.
  • broker: Valkey, Redis uyumlu bir anahtar-değer deposudur. Web süreci ile çalışanlar arasındaki görev kuyruğudur.
  • gotenberg ve tika: isteğe bağlıdır, yalnızca -tika compose varyantlarında bulunur. Office belgelerini (.docx, .xlsx, .odt) PDF formatına dönüştürürler, böylece paperless bunları dizine ekleyebilir.

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.

Ön gereksinimler

  • Sudo erişimine sahip bir Ubuntu 24.04 KVM VPS ve halihazırda kurulu Docker Compose eklentisi. Eğer bu kısım sizin için yeniyse, önce VPS için Docker Compose temelleri rehberine göz atıp geri dönün.
  • VPS'in IP adresine yönlendirilmiş bir A kaydına sahip alan adı. Paperless, kendisine tanımlanmamış bir ana makine adında (hostname) hizmet vermeyi reddeder; bu nedenle bu adım beklediğinizden daha önemlidir.
  • Bellek, asıl kısıtlayıcı faktördür. PostgreSQL, Valkey, gunicorn ve Tesseract OCR işleyicisi aynı anda çalıştığında, hafif kullanım için 2 GB bellek yeterlidir. Eğer yüzlerce taramadan oluşan bir arşivi içe aktarmayı planlıyorsanız 4 GB bellek ayırın; çünkü büyük ve çok sayfalı PDF dosyalarında OCR işlemi, çekirdeğin (kernel) bellek yetersizliği (OOM) nedeniyle bir işleyiciyi sonlandırmasına yol açabilecek bellek sıçramalarına neden olur.
  • Disk: Arşiviniz, orijinal dosya ve OCR işleminden geçmiş arşiv PDF'i olmak üzere iki kez saklanır; bu nedenle taramalarınızın toplam boyutunun yaklaşık iki katı kadar disk alanı ayırın.

Resmi compose dosyalarını edinme

Etkileşimli bir yükleyici mevcuttur:

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

Bu yükleyici size sorular sorar ve dosyaları sizin yerinize oluşturur. İşlemi manuel olarak yapmak dört komut sürer ve her şeyin nerede olduğunu bilmenizi sağlar; yönettiğiniz bir sunucuda istediğiniz durum tam olarak budur.

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

Varyantlar aynı dizinde bulunur: docker-compose.sqlite.yml, docker-compose.mariadb.yml ve her birinin bir -tika sürümü. Yeni bir kurulum için postgres seçin. SQLite birkaç yüz doküman için uygundur ancak tam metin arama dizini, PostgreSQL'den çok daha önce yavaşlamaya başlar.

.env dosyası tek bir satır içerir: COMPOSE_PROJECT_NAME=paperless. Bu isim, her container ve volume için önek haline gelir; bu yüzden dosyayı silmeyin, aksi takdirde docker compose down -v neden verilerinizi bulamıyor diye merak edersiniz.

docker-compose.env dosyasını ilk başlatmadan önce yapılandırın

İki ayar isteğe bağlı değildir. Proje belgelerinde belirtilen komutu kullanarak gizli anahtarı 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=1000

PAPERLESS_SECRET_KEY, varsayılan olarak change-me değeriyle gelir. Bu değer oturum çerezlerini imzalar; bu nedenle varsayılan değeri bırakmak, varsayılanı bilen herkesin oturum sahteciliği yapmasına olanak tanır. Değeri ilk başlatmadan önce ayarlayın, çünkü daha sonra değiştirmek tüm kullanıcıların oturumunu sonlandırır.

PAPERLESS_URL, size zaman kazandıracak olan ayardır. Paperless bir Django uygulamasıdır ve Django her isteğin Host başlığını doğrular. PAPERLESS_URL değerini ayarladığınızda, uygulama sizin yerinize ALLOWED_HOSTS, CORS_ALLOWED_HOSTS ve CSRF_TRUSTED_ORIGINS değerlerini doldurur. Bu alanı boş bırakıp bir alan adını sunucuya yönlendirirseniz, her sayfa Bad Request (400) hatası döndürür ve container günlüğünde DisallowedHost mesajı görünür. Değeri, sonunda eğik çizgi (slash) veya yol olmadan yazın.

USERMAP_UID ve USERMAP_GID, container'ın hangi kullanıcı yetkileriyle çalışacağını belirler. Bu değerleri, id -u ve id -g komutlarıyla kontrol edebileceğiniz kendi kullanıcı hesabınızla eşleştirin. Değerler eşleşmezse, consume klasörüne kopyaladığınız dosyalar tüketici (consumer) tarafından okunamayacak ve günlük kayıtlarında içe aktarma hatası yerine izin hatası görünecektir.

Stack'i başlatın ve ilk kullanıcıyı oluşturun

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

createsuperuser bir kullanıcı adı, e-posta adresi ve parola ister. Varsayılan bir giriş bilgisi bulunmadığından, bu adımı atlamak sizi hiçbir bilginin kabul edilmeyeceği bir giriş sayfasına yönlendirir. Tarayıcı üzerinden erişim sağlamadan önce sunucunun 8000 numaralı portta dinleme yaptığını belirten log satırını bekleyin. İlk başlatma işlemi aynı zamanda veritabanı migrasyonlarını da çalıştırır; bu süreç bir veya iki dakika sürebilir.

Bir alan adı eklemeden önce yerel olarak kontrol edin:

curl -I http://127.0.0.1:8000

302 üzerinden /accounts/login/ adresine yönlendirme yapılması, stack'in sağlıklı çalıştığı anlamına gelir.

Önüne HTTPS ekleyin

Varsayılan compose dosyası, tüm arayüzlere bağlanan 8000:8000 portunu dışarıya açar. Bu durum, tüm belge arşivinizi adresi bulan herkese şifrelenmemiş HTTP üzerinden sunan halka açık bir VPS üzerinde güvenlik riski oluşturur. Port satırını yalnızca loopback arayüzüne bağlanacak şekilde değiştirin:

    ports:
      - "127.0.0.1:8000:8000"

Ardından TLS (transport layer security) sonlandırma işlemini bir reverse proxy üzerinde gerçekleştirin ve trafiği 127.0.0.1:8000 adresine yönlendirin. Eğer sunucuda çalışan tek uygulama buysa, ACME (automatic certificate management environment) istemcisine sahip herhangi bir proxy yeterli olacaktır. Eğer tek bir sertifika yapısı arkasında birden fazla container çalıştırıyorsanız, birden fazla Docker Compose uygulaması için Traefik reverse proxy modeli rehberini izleyin ve webserver servisini, dışarıya herhangi bir port açmadan proxy ağına dahil edin.

Hangi proxy'yi kullanırsanız kullanın, X-Forwarded-Proto: https başlığını iletmesi gerekir. Bu başlık olmadan Django, isteğin HTTP üzerinden geldiğini varsayar, giriş formundaki kaynak (origin) denetimi başarısız olur ve doğru görünen bir sayfada CSRF verification failed. Request aborted. hatası alırsınız. Bu sorunun diğer çözüm adımı ise PAPERLESS_URL ayarının, tarayıcıya yazdığınız tam https:// adresine göre yapılandırılmasıdır.

Ayrıca proxy'nin dosya yükleme boyutu sınırını yükseltin. Proxy tarafından gövde boyutu 1 MB ile sınırlandırılmış bir bağlantı üzerinden gönderilen 40 MB'lık bir tarama dosyası, Paperless'a ulaşmadan reddedilir ve tarayıcı genel bir yükleme hatası bildirir.

Consume dizini nasıl çalışır

Compose dosyası, compose dizinindeki ./consume dizinini container içine bind-mount yöntemiyle bağlar. Buraya koyduğunuz her dosya içeri aktarılır ve ardından klasörden silinir; çünkü dosya artık paperless yönetimi altındaki medya biriminde yaşamaktadır.

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

Consumer'ın dosya adını aldığını, OCR işlemini çalıştırdığını ve belgenin eklendiğini bildiren bir satırla işlemi tamamladığını görmelisiniz. Tüm döngü, tek sayfalık bir tarama için saniyeler sürerken, uzun bir belge için bir dakika veya daha fazla sürebilir.

İki ayar, dosyaların nasıl bulunduğunu değiştirir. PAPERLESS_CONSUMER_RECURSIVE=true ayarı, paperless'ın alt klasörlere bakmasını sağlar; PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true ise her alt klasör adını bir etikete dönüştürür. Böylece bir dosyayı consume/invoices/2026/ içine bırakmak, dosyayı invoices ve 2026 etiketleriyle etiketler. Bu, şimdiye kadar oluşturabileceğiniz en düşük maliyetli dosyalama sistemidir.

Algılama, işin diğer yarısıdır. Varsayılan olarak PAPERLESS_CONSUMER_POLLING_INTERVAL değeri 0 olarak ayarlanmıştır; bu, paperless'ın anında tetiklenen çekirdek dosya sistemi bildirimlerini kullandığı anlamına gelir. Bu bildirimler ağ dosya sistemleri üzerinden iletilmez. Eğer consume klasörünüz bir ağ tarayıcısının yazabilmesi için NFS veya SMB paylaşımı ise, hiçbir dosya algılanmaz. Bu durumun çözümü, aralığı pozitif bir saniye değerine ayarlayarak paperless'ın klasörü düzenli aralıklarla taramasını sağlamaktır.

OCR dilleri ve maliyetleri

PAPERLESS_OCR_LANGUAGE, üç harfli bir Tesseract kodu alır; varsayılan değer eng şeklindedir. Dilleri birleştirmek için deu+eng örneğinde olduğu gibi artı işareti kullanın. Tesseract her bir dili dener ve en iyi sonucu saklar; bu nedenle eklenen her dil, her sayfa için harcanan CPU süresini katlar. Paylaşımlı vCPU kullanan bir VPS üzerinde bu, tarama işleminin on saniyede bitmesi ile bir dakikada bitmesi arasındaki farkı yaratır. Yalnızca belgelerinizin gerçekten yazıldığı dilleri listeleyin.

İmaj; İngilizce, Almanca, İtalyanca, İspanyolca ve Fransızca dilleriyle gelir. Başka bir dil için, dili PAPERLESS_OCR_LANGUAGES değişkenine boşlukla ayrılmış bir liste olarak ekleyin (örneğin PAPERLESS_OCR_LANGUAGES=tur ces) ve servisi yeniden başlatın. Container, Tesseract veri paketlerini başlangıçta indirir; bu nedenle değişiklikten sonraki ilk açılış daha yavaş gerçekleşir.

Veritabanı ve medya yedekleme

PostgreSQL çalışırken Docker volume dizinlerini kopyalamak, geri yüklenemeyebilecek bir yedek oluşturmanıza neden olur. Paperless kendi dışa aktarma aracını sunar; bu araç, belgeleri ve tüm metadata bilgilerini içeren bir JSON manifest dosyasını ./export bind mount dizinine yazar:

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ı siler; böylece klasör sürekli büyümek yerine güncel bir yansıma olarak kalır. --no-progress-bar, bu işlem cron üzerinden çalıştırıldığında çıktıların temiz kalmasını sağlar.

Geri yükleme işlemi, yeni bir yığın üzerinde aynı klasör kullanılarak document_importer ile yapılır; bu da dışa aktarma dizinini güvenli tutmanız gereken tek yer haline getirir. Bu dizini VPS üzerinden şifrelenmiş ve tekilleştirilmiş restic yedekleri ile düzenli olarak sunucu dışına gönderin ve restic'in yarım kalmış bir arşivi yedeklememesi için dışa aktarma işlemini önce çalıştırın.

export/manifest.json öğesinin mevcut olduğunu ve dosya sayısının arayüzdeki belge sayınızla eşleştiğini kontrol ederek yedeği doğrulayın. Hiç listelenmemiş bir yedek, yedek değildir. Her gece alınan dışa aktarma işleminin sessizce başarısız olmaya başlaması daha da kötüdür. Bu nedenle cron job, çıkış durumunu kendi ntfy sunucunuza göndersin. Böylece geri yükleme yapmanız gereken günü beklemek yerine sorunun başladığı haftadan haberdar olursunuz.

FAQ

Alan adımı yönlendirdikten sonra neden her sayfa "Bad Request (400)" hatası veriyor?

Django, alan adınız ALLOWED_HOSTS içinde tanımlı olmadığı için Host başlığını reddediyordur. docker-compose.env dosyasında PAPERLESS_URL=https://paperless.example.com değerini, sonunda eğik çizgi (slash) olmadan ayarlayın ve ardından container'ı yeniden oluşturmak için docker compose up -d komutunu çalıştırın. Yalnızca env dosyasını düzenlemek bir sonuç vermez, çünkü çalışan container başlatıldığı andaki ortam değişkenlerini korur.

consume klasörüne bir PDF attım ancak hiçbir şey olmadı. Sorun nedir?

Öncelikle docker compose logs webserver dosyasını kontrol edin. Bir izin hatası, USERMAP_UID ve USERMAP_GID değerlerinin dosyanın sahibi olan hesapla eşleşmediği anlamına gelir; bu değerleri düzeltip container'ı yeniden oluşturun. Hiçbir log kaydı oluşmuyorsa, dosya olayı hiç ulaşmamış demektir; bu durum ağ paylaşımlarında yaşanır çünkü çekirdek (kernel) bildirimleri ağ paylaşımları üzerinden iletilmez. Bunun yerine PAPERLESS_CONSUMER_POLLING_INTERVAL değerini 30 gibi bir süreye ayarlayın; böylece paperless klasörü 30 saniyede bir tarayacaktır.

paperless-ngx uygulamasını PostgreSQL yerine SQLite ile çalıştırabilir miyim?

Evet, docker-compose.sqlite.yml desteklenmektedir ve daha az bellek tüketir; bu da küçük bir VPS için uygundur. Ancak arşiviniz büyüdükçe dezavantajı ortaya çıkar: binlerce dokümanlık bir arşivde tam metin araması ve toplu etiket düzenlemeleri belirgin şekilde yavaşlar. Daha sonra geçiş yapmak bir dışa aktarma ve içe aktarma işlemi gerektirir, bu nedenle arşivinizin büyüyeceğini öngörüyorsanız şimdiden PostgreSQL seçin.

Taranmış belgelerden oluşan bir arşiv aslında ne kadar disk alanına ihtiyaç duyar?

Kaynak dosyalarınızın boyutunun kabaca iki katına. Paperless, orijinal dosyayı değiştirmeden saklar ve üzerine aranabilir bir metin katmanı eklenmiş ikinci bir OCR'lı PDF ile küçük önizleme görselleri oluşturur. Sadece metin içeren 200 KB'lık bir tarama küçük kalır. Uzun bir sözleşmenin 30 MB'lık renkli taraması yaklaşık 60 MB yer kaplar. Eğer dışa aktarma (export) dizinini de aynı diskte tutuyorsanız, aynı arşiv diskte üç kez yer kaplamış olur.

Tika ve Gotenberg container'larına ihtiyacım var mı?

Yalnızca Word, Excel veya OpenDocument dosyalarınızın PDF'lerinizle birlikte indekslenmesini istiyorsanız gereklidir. Bu servisler, paperless uygulamasının OCR yapabilmesi ve arama gerçekleştirebilmesi için bu formatları PDF'e dönüştürür. Ayrıca iki ek container çalıştırırlar ve birkaç yüz megabayt bellek tüketirler; bu nedenle arşivlediğiniz her şey zaten PDF veya görsel ise küçük bir sunucuda bunları kullanmayabilirsiniz.

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