diff --git a/docker/compose/docker-compose.env b/docker/compose/docker-compose.env index e9e8ecb06..34e694b92 100644 --- a/docker/compose/docker-compose.env +++ b/docker/compose/docker-compose.env @@ -22,6 +22,10 @@ # Docker setup does not use the configuration file. # A few commonly adjusted settings are provided below. +# This is required if you will be exposing Paperless-ngx on a public domain +# (if doing so please consider security measures such as reverse proxy) +#PAPERLESS_URL=https://paperless.example.com + # Adjust this key if you plan to make paperless available publicly. It should # be a very long sequence of random characters. You don't need to remember it. #PAPERLESS_SECRET_KEY=change-me diff --git a/docs/configuration.rst b/docs/configuration.rst index 192fa8513..9a59a80ba 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -142,7 +142,24 @@ PAPERLESS_SECRET_KEY= Default is listed in the file ``src/paperless/settings.py``. -PAPERLESS_ALLOWED_HOSTS +PAPERLESS_URL= + This setting can be used to set the three options below (ALLOWED_HOSTS, + CORS_ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS). If the other options are + set the values will be combined with this one. Do not include a trailing + slash. E.g. https://paperless.domain.com + + Defaults to empty string, leaving the other settings unaffected. + +PAPERLESS_CSRF_TRUSTED_ORIGINS= + A list of trusted origins for unsafe requests (e.g. POST). As of Django 4.0 + this is required to access the Django admin via the web. + See https://docs.djangoproject.com/en/4.0/ref/settings/#csrf-trusted-origins + + Can also be set using PAPERLESS_URL (see above). + + Defaults to empty string, which does not add any origins to the trusted list. + +PAPERLESS_ALLOWED_HOSTS= If you're planning on putting Paperless on the open internet, then you really should set this value to the domain name you're using. Failing to do so leaves you open to HTTP host header attacks: @@ -151,12 +168,16 @@ PAPERLESS_ALLOWED_HOSTS Just remember that this is a comma-separated list, so "example.com" is fine, as is "example.com,www.example.com", but NOT " example.com" or "example.com," + Can also be set using PAPERLESS_URL (see above). + Defaults to "*", which is all hosts. -PAPERLESS_CORS_ALLOWED_HOSTS +PAPERLESS_CORS_ALLOWED_HOSTS= You need to add your servers to the list of allowed hosts that can do CORS calls. Set this to your public domain name. + Can also be set using PAPERLESS_URL (see above). + Defaults to "http://localhost:8000". PAPERLESS_FORCE_SCRIPT_NAME= diff --git a/install-paperless-ngx.sh b/install-paperless-ngx.sh index 1eb689c85..6ffcefbb6 100755 --- a/install-paperless-ngx.sh +++ b/install-paperless-ngx.sh @@ -92,6 +92,14 @@ echo "" echo "1. Application configuration" echo "============================" +echo "" +echo "The URL paperless will be available at. This is required if the" +echo "installation will be accessible via the web, otherwise can be left blank." +echo "" + +ask "URL" "" +URL=$ask_result + echo "" echo "The port on which the paperless webserver will listen for incoming" echo "connections." @@ -278,6 +286,7 @@ if [[ "$DATABASE_BACKEND" == "postgres" ]] ; then fi fi echo "" +echo "URL: $URL" echo "Port: $PORT" echo "Database: $DATABASE_BACKEND" echo "Tika enabled: $TIKA_ENABLED" @@ -313,6 +322,9 @@ SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 64 | head -n 1) DEFAULT_LANGUAGES="deu eng fra ita spa" { + if [[ ! $URL == "" ]] ; then + echo "PAPERLESS_URL=$URL" + fi if [[ ! $USERMAP_UID == "1000" ]] ; then echo "USERMAP_UID=$USERMAP_UID" fi diff --git a/paperless.conf.example b/paperless.conf.example index de24bde74..0b37e210d 100644 --- a/paperless.conf.example +++ b/paperless.conf.example @@ -27,8 +27,10 @@ # Security and hosting #PAPERLESS_SECRET_KEY=change-me -#PAPERLESS_ALLOWED_HOSTS=example.com,www.example.com -#PAPERLESS_CORS_ALLOWED_HOSTS=http://example.com,http://localhost:8000 +#PAPERLESS_URL=https://example.com +#PAPERLESS_CSRF_TRUSTED_ORIGINS=https://example.com # can be set using PAPERLESS_URL +#PAPERLESS_ALLOWED_HOSTS=example.com,www.example.com # can be set using PAPERLESS_URL +#PAPERLESS_CORS_ALLOWED_HOSTS=https://localhost:8080,https://example.com # can be set using PAPERLESS_URL #PAPERLESS_FORCE_SCRIPT_NAME= #PAPERLESS_STATIC_URL=/static/ #PAPERLESS_AUTO_LOGIN_USERNAME= diff --git a/src/paperless/settings.py b/src/paperless/settings.py index 023f2fa2c..30d6e87c4 100644 --- a/src/paperless/settings.py +++ b/src/paperless/settings.py @@ -4,6 +4,7 @@ import multiprocessing import os import re from typing import Final +from urllib.parse import urlparse from concurrent_log_handler.queue import setup_logging_queues from django.utils.translation import gettext_lazy as _ @@ -219,7 +220,15 @@ if DEBUG: else: X_FRAME_OPTIONS = "SAMEORIGIN" -# We allow CORS from localhost:8080 + +# The next 3 settings can also be set using just PAPERLESS_URL +_csrf_origins = os.getenv("PAPERLESS_CSRF_TRUSTED_ORIGINS") +if _csrf_origins: + CSRF_TRUSTED_ORIGINS = _csrf_origins.split(",") +else: + CSRF_TRUSTED_ORIGINS = [] + +# We allow CORS from localhost:8000 CORS_ALLOWED_ORIGINS = tuple( os.getenv("PAPERLESS_CORS_ALLOWED_HOSTS", "http://localhost:8000").split(","), ) @@ -228,6 +237,22 @@ if DEBUG: # Allow access from the angular development server during debugging CORS_ALLOWED_ORIGINS += ("http://localhost:4200",) +_allowed_hosts = os.getenv("PAPERLESS_ALLOWED_HOSTS") +if _allowed_hosts: + ALLOWED_HOSTS = _allowed_hosts.split(",") +else: + ALLOWED_HOSTS = ["*"] + +_paperless_url = os.getenv("PAPERLESS_URL") +if _paperless_url: + _paperless_uri = urlparse(_paperless_url) + CSRF_TRUSTED_ORIGINS.append(_paperless_url) + CORS_ALLOWED_ORIGINS += (_paperless_url,) + if _allowed_hosts: + ALLOWED_HOSTS.append(_paperless_uri.hostname) + else: + ALLOWED_HOSTS = [_paperless_uri.hostname] + # The secret key has a default that should be fine so long as you're hosting # Paperless on a closed network. However, if you're putting this anywhere # public, you should change the key to something unique and verbose. @@ -236,12 +261,6 @@ SECRET_KEY = os.getenv( "e11fl1oa-*ytql8p)(06fbj4ukrlo+n7k&q5+$1md7i+mge=ee", ) -_allowed_hosts = os.getenv("PAPERLESS_ALLOWED_HOSTS") -if _allowed_hosts: - ALLOWED_HOSTS = _allowed_hosts.split(",") -else: - ALLOWED_HOSTS = ["*"] - AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",