Skip to content

Environment variables

These are the variables in the install guides’ compose.yaml and .env files. Basic Compose installs keep .env beside compose.yaml; HTTPS installs keep .env beside the release configuration folder. Select the platform version in .env; PostgreSQL has an independent version. The generated .env and its manual example contain the same settings and comments; only the shortened secret examples are replaced with independent random values. For how to generate, protect and change secrets, see Configuration and secrets.

Variable Purpose
COMPOSE_PROJECT_NAME Optional Compose instance name. Basic Compose defaults to lunarpaper; Publisher defaults to lunarpaper-publisher. Select a previously unused name for fresh named volumes. An explicit --project-name flag takes precedence, as in the HTTPS guide. It has no effect on docker run.
LUNAR_PAPER_VERSION Published platform version, such as 0.8.1. Selects ghcr.io/lunarpaper/platform:<version>.
LUNAR_PAPER_IMAGE Optional image repository override, without a tag (for example ghcr.io/lunarpaper/platform). Defaults to the public repository. Compose appends LUNAR_PAPER_VERSION and forwards the combined reference to the app.
PGUSER PostgreSQL owner username for setup, upgrades and backups. Defaults to postgres. See Database usernames.
APP_PLATFORM_USER Platform runtime login name. Defaults to app_platform.
APP_INTAKE_USER Intake runtime login name. Defaults to app_intake.
POSTGRES_IMAGE Optional PostgreSQL image selection; defaults to official postgres:17-alpine. Keep major version 17. It is independent of the platform version.
HOST_PORT HTTP host port; defaults to 3000. Used by the basic Compose and Docker Run examples. Include any changed port in APP_URL. Does not change Caddy’s HTTPS ports or the publisher’s port.
HTTP_BIND_ADDRESS Optional HTTP interface; defaults to 127.0.0.1. Set a server interface IP for LAN access.
APP_URL The exact address people open in their browser, such as http://192.168.1.20:3000.
SYSTEM_ADMIN_USERNAME The email address of the first administrator, created during guided setup.
SYSTEM_ADMIN_PASSWORD The password of the first administrator. It needs 12 or more characters, with upper case, lower case, a number and a symbol.
CADDY_TLS_DIRECTIVE Used only in the HTTPS guide. Set it to tls internal on a private network, or tls you@example.com to get a public certificate.
COOKIE_NAMESPACE Optional cookie prefix: 1–32 letters, numbers, _ or -. Use a different value for each additional instance on the same hostname; browser cookies are shared across ports.
PUBLISHER_PRIVATE_TARGETS Optional. Publishing instances on your own network that Lunar Paper may send content to, as host:port, separated by commas. See Set up a publishing instance.
Running multiple instances

For a fresh basic Compose installation beside an existing one, generate a new .env in a separate folder, then set:

COMPOSE_PROJECT_NAME=lunarpaper-test
HOST_PORT=3100
HTTP_BIND_ADDRESS=127.0.0.1
APP_URL=http://localhost:3100
COOKIE_NAMESPACE=lunarpaper_test

Choose an unused project name and port. Keep the default volume settings for separate project-prefixed storage, such as lunarpaper-test_postgres-data. Custom host folder paths must also be unique. A new folder alone does not override the fixed Compose project name; new secrets do not reset an existing database. See Running multiple instances.

HTTPS commands explicitly select a project name, Arcane manages its project identity, and Docker Run uses fixed names. Follow each guide’s multiple-instance section rather than applying this block unchanged to those methods.

The generated .env includes these defaults, exactly as in the manual example:

PGUSER=postgres
APP_PLATFORM_USER=app_platform
APP_INTAKE_USER=app_intake

You can manually override any of these before the first start and keyed web setup. Use three distinct names. For custom names, start with a lowercase letter, followed by lowercase letters, digits or underscores, up to 63 characters. Keep app_*, pg_*, postgres, public, svc_datalayer and reporting reserved, except for the defaults shown above. For example, paper_owner, paper_platform and paper_intake are suitable overrides.

Each account has its own generated password: PGPASSWORD, APP_PLATFORM_PASSWORD and APP_INTAKE_PASSWORD. Compose uses the same settings for the PostgreSQL owner, application connections and keyed setup. Custom application logins inherit the existing restricted permission roles; the owner remains separate.

These are fresh-install settings. Changing .env does not rename users or rotate passwords in an existing database. Keep your current values across upgrades; changing an established installation needs coordinated database-role and deployment configuration changes by the operator. Do not recreate data volumes to change a username.

For Compose installations, these optional settings select each service’s storage source. They default to the existing Docker-managed named volumes. Use an absolute host folder path to select a bind mount instead. See Choose storage locations.

Variable Default Stores
POSTGRES_DATA postgres-data PostgreSQL data at /var/lib/postgresql/data.
REDIS_DATA redis-data Redis data at /data.
UPLOADS_DATA uploads-data Application uploads at /app/uploads.
SEAWEEDFS_DATA seaweedfs-data SeaweedFS file contents and index at /data.

Named volumes receive the effective Compose project prefix. The default POSTGRES_DATA=postgres-data becomes lunarpaper_postgres-data; changing the project name selects different named storage. Arbitrary new volume names need matching declarations in compose.yaml.

Changing a value does not move existing data. Back up and migrate the data before changing storage for an existing installation. Reusing existing storage requires its original credentials and encryption keys, even if the containers were removed.

The install guides generate each value independently using 32 random bytes. There are no shared default database passwords. Preserve these values after the first start; changing a password in .env does not change the password stored in PostgreSQL.

Variable Purpose
SETUP_KEY Unlocks initial guided setup and database upgrades.
SESSION_SECRET Signs sign-in sessions.
ENCRYPTION_KEY Encrypts form submissions and publishing data.
INTERNAL_API_TOKEN Authenticates requests between Lunar Paper’s own services.
AI_ENCRYPTION_KEY Encrypts saved AI provider credentials.
MFA_ENCRYPTION_KEY Encrypts two-factor sign-in secrets.
SSO_ENCRYPTION_KEY Encrypts single sign-on client secrets.
DATA_SOURCE_ENCRYPTION_KEY Encrypts data source credentials, proxy profiles and the licence activation.
WORKFLOW_CREDENTIAL_ENCRYPTION_KEY Encrypts credentials saved for workflows.
PUBLISHER_CREDENTIAL_ENCRYPTION_KEY Encrypts form publisher credentials.
EMAIL_ENCRYPTION_KEY Encrypts outbound email connector credentials.
ADDRESS_PROVIDER_ENCRYPTION_KEY Encrypts map and address provider credentials.
EMAIL_TRACKING_SECRET Signs email open and click tracking links.
PDF_EXPORT_SECRET Signs PDF export requests.
FORM_FILE_ENCRYPTION_KEYS Keys that encrypt files uploaded through forms, in the form {"v1":"<key>"}.
PGPASSWORD Password of the PostgreSQL owner account, used for setup, upgrades and backups.
APP_PLATFORM_PASSWORD Password of the restricted account selected by APP_PLATFORM_USER. The platform initializer configures it on fresh installation; preserve it on upgrades.
APP_INTAKE_PASSWORD Password of the restricted account selected by APP_INTAKE_USER. The platform initializer configures it on fresh installation; preserve it on upgrades.
REDIS_PASSWORD Password for Redis.

The internal permission roles app_platform and app_intake remain stable for migrations. Custom login names inherit their respective permissions; do not use the owner for runtime connections.

These have fixed values in compose.yaml, and you do not need to change them.

Variable Purpose
NODE_ENV Runs Lunar Paper in production mode.
PORT The port Lunar Paper listens on inside its container: 3000.
PROCESS_ROLE Which parts run in the container. all runs the web app and background jobs together.
CLUSTER_WORKERS Web worker count. The standard single-container installation uses 1.
TRUST_PROXY_HOPS How many proxies sit in front of Lunar Paper: 0 for direct access, 1 behind Caddy.
API_URL The API address, set to APP_URL.
ALLOWED_ORIGINS Browser origins allowed to call the API, set to APP_URL.
PUBLISHER_CALLBACK_ORIGINS Origins allowed to receive form publisher callbacks, set to APP_URL.
LUNAR_PAPER_IMAGE Resolved platform image reference, identical to the container image selected above. Used for release checks.
FORM_FILE_ENCRYPTION_ACTIVE_KEY_ID Which key in FORM_FILE_ENCRYPTION_KEYS encrypts new files: v1.
PGHOST, PGPORT, PGDATABASE Where the PostgreSQL owner account connects: postgres, 5432, platform.
DATABASE_URL Connection to the platform database for day-to-day use.
INTAKE_DATABASE_URL Connection to the intake database for day-to-day use.
MIGRATION_PLATFORM_DATABASE_URL Owner connection to the platform database, used for explicit initialization and upgrades.
MIGRATION_INTAKE_DATABASE_URL Owner connection to the intake database, used for explicit initialization and upgrades.
APP_DB_ROLE Makes Lunar Paper use the restricted database accounts.
DB_POOL_MAX Maximum database connections per pool: 40.
SESSION_STORE Where sessions are kept: redis.
REDIS_REQUIRED Stops Lunar Paper from starting without Redis: true.
REDIS_HOST, REDIS_PORT Where Redis is: redis, 6379.
SEAWEEDFS_MASTER_URL, SEAWEEDFS_FILER_URL, SEAWEEDFS_VOLUME_URL Addresses of the file storage service.

The official PostgreSQL container receives POSTGRES_DB, POSTGRES_USER and POSTGRES_PASSWORD. These create its cluster and empty platform database only when its data directory is empty. POSTGRES_USER comes from PGUSER and POSTGRES_PASSWORD comes from PGPASSWORD. Changing these settings does not rename an existing owner or rotate its password in an existing volume. Runtime passwords go to the platform initializer; official PostgreSQL does not interpret APP_PLATFORM_PASSWORD or APP_INTAKE_PASSWORD. No Lunar Paper database image or paired digest is needed.

The publisher has a separate .env and no PostgreSQL database. Copy its credentials from Publisher Inventory; do not run the main application’s secret generator for it. See Set up a publishing instance.

Variable Purpose
LUNAR_PAPER_VERSION Publisher tag matching the main platform release.
PUBLISHER_IMAGE Optional repository override without a tag; defaults to ghcr.io/lunarpaper/publisher.
PUBLISHER_HOST_PORT Publisher host port; defaults to 8081. Container port remains 8080. Register the chosen host port in Publisher Inventory.
PUBLISHER_BIND_ADDRESS Interface to publish on; defaults to 0.0.0.0 for reachability from the main app. Use an assigned server IP to restrict interfaces, or loopback behind a proxy on the same host.
PUBLISHER_DATA Storage source at /app/data; defaults to the project-prefixed publisher-data named volume. An absolute host path selects a bind mount.
MAIN_APP_URL Reachable main platform address, matching its APP_URL. This is not the publisher’s address or port.
PUBLISHER_INSTANCE_ID, API_KEY, PUBLISHER_BROKER_TOKEN Connection settings copied from Publisher Inventory. Preserve them with existing content.
ASSET_ENCRYPTION_KEY Publisher’s asset key; retain it with its stored content.
EMAIL_TRACKING_SECRET Email tracking key. When using tracking, match the main installation’s value.
PUBLISHER_TRUST_PROXY_HOPS 0 for direct access; set 1 behind one reverse proxy.

Add these to the lunarpaper service in compose.yaml only if you need them.

Variable Purpose
ADDRESS_SELF_HOSTED_NOMINATIM_URL Address of your own Nominatim or Photon server for address lookup. See Address lookup.
NODE_EXTRA_CA_CERTS Path to a root certificate, inside the container, for an outbound proxy that inspects TLS.
RENDER_BASE_URL The address the built-in headless browser opens to take homepage screenshots and render dashboard exports. Leave it unset: each container uses its own internal address. Set it only if Administration > System Configuration > Thumbnails says screenshots are paused because that address is unreachable or redirected.
CONTENT_CAPTURE_CONCURRENCY How many homepage screenshots a container takes at once. The default is 1. See Screenshots and exports.