Install with Arcane
Arcane is a web interface for managing Docker. This guide creates a Lunar Paper project in Arcane from the configuration used by the Docker Compose guides. You can serve Lunar Paper over HTTP on host port 3000 by default, choose another host port, or use HTTPS through Caddy on ports 80 and 443.
Before you start
Section titled “Before you start”- Install Arcane on the server, and make sure you can sign in to it as an administrator. See the Arcane documentation.
- For HTTP, choose an unused host port. The example uses 3000, but you can change it. For HTTPS, make sure ports 80 and 443 are free and that your name points at the server. See Choose your address and certificate.
- Choose a published platform release.
These examples target 0.8.1 in
lunarpaper/lunarpaper.
The public image must be published
before you can pull it. PostgreSQL uses official
postgres:17-alpineindependently. - Open a terminal on any computer. You need it for step 1.
- Linux and macOS need OpenSSL for secret generation. The HTTP configuration uses inline configs and requires Docker Compose 2.23.1 or later on the server.
Running multiple instances
Create a separate Arcane project with a previously unused name. For HTTP, change
name: lunarpaper in the pasted Compose file to match. Use a different HOST_PORT,
update APP_URL, and set a unique COOKIE_NAMESPACE when sharing a hostname.
Check Arcane’s effective Compose project name before deploying; it determines
container, network and named-volume identities.
Keep the default named-volume settings to separate storage by project. If you use
host folders instead, choose different folders for each instance. A new .env
does not reset existing database passwords. Keep the original secrets when reusing
storage. For HTTPS, ports 80 and 443 must also be free; otherwise use HTTP behind
an existing reverse proxy.
Install
Section titled “Install”-
Generate the secrets. Run this in a terminal and save the output in a password manager. Use new secrets only for a fresh installation.
Terminal window for name in SETUP_KEY PGPASSWORD APP_PLATFORM_PASSWORD APP_INTAKE_PASSWORD REDIS_PASSWORD \SESSION_SECRET ENCRYPTION_KEY INTERNAL_API_TOKEN AI_ENCRYPTION_KEY MFA_ENCRYPTION_KEY \SSO_ENCRYPTION_KEY DATA_SOURCE_ENCRYPTION_KEY WORKFLOW_CREDENTIAL_ENCRYPTION_KEY \PUBLISHER_CREDENTIAL_ENCRYPTION_KEY EMAIL_ENCRYPTION_KEY ADDRESS_PROVIDER_ENCRYPTION_KEY \EMAIL_TRACKING_SECRET PDF_EXPORT_SECRET; doecho "$name=$(openssl rand -hex 32)"doneecho "FORM_FILE_ENCRYPTION_KEYS={\"v1\":\"$(openssl rand -hex 32)\"}"Terminal window $rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()function New-Hex { $b = New-Object byte[] 32; $rng.GetBytes($b); ([BitConverter]::ToString($b) -replace '-', '').ToLower() }foreach ($n in 'SETUP_KEY', 'PGPASSWORD', 'APP_PLATFORM_PASSWORD', 'APP_INTAKE_PASSWORD', 'REDIS_PASSWORD','SESSION_SECRET', 'ENCRYPTION_KEY', 'INTERNAL_API_TOKEN', 'AI_ENCRYPTION_KEY', 'MFA_ENCRYPTION_KEY','SSO_ENCRYPTION_KEY', 'DATA_SOURCE_ENCRYPTION_KEY', 'WORKFLOW_CREDENTIAL_ENCRYPTION_KEY','PUBLISHER_CREDENTIAL_ENCRYPTION_KEY', 'EMAIL_ENCRYPTION_KEY', 'ADDRESS_PROVIDER_ENCRYPTION_KEY','EMAIL_TRACKING_SECRET', 'PDF_EXPORT_SECRET') { "$n=$(New-Hex)" }'FORM_FILE_ENCRYPTION_KEYS={"v1":"' + (New-Hex) + '"}' -
Create the project. In Arcane, open Projects, select Create Project, and rename My New Project to
lunarpaper. -
Paste the Compose configuration. Expand your chosen option and copy it into Docker Compose File.
HTTP: copy compose.yaml
Use this complete configuration for basic HTTP. File-storage settings are included; no supporting files are needed.
compose.yaml # Lunar Paper with official PostgreSQL. Select the platform version in your private environment.# Initialize or upgrade application schemas explicitly through protected web setup.name: lunarpaperservices:lunarpaper:image: ${LUNAR_PAPER_IMAGE:-ghcr.io/lunarpaper/platform}:${LUNAR_PAPER_VERSION:?LUNAR_PAPER_VERSION is required}restart: unless-stoppedenvironment:NODE_ENV: productionPORT: "3000"PROCESS_ROLE: allCLUSTER_WORKERS: "1"# One browser URL controls origins and cookie security for HTTP.APP_URL: ${APP_URL:?APP_URL is required}API_URL: ${APP_URL:?APP_URL is required}ALLOWED_ORIGINS: ${APP_URL:?APP_URL is required}PUBLISHER_CALLBACK_ORIGINS: ${APP_URL:?APP_URL is required}# Keyed web setup and manual upgrades are fixed application behaviour.SETUP_KEY: ${SETUP_KEY:?SETUP_KEY is required}# Forward the same image selection to the app's release checks.LUNAR_PAPER_IMAGE: ${LUNAR_PAPER_IMAGE:-ghcr.io/lunarpaper/platform}:${LUNAR_PAPER_VERSION:?LUNAR_PAPER_VERSION is required}SYSTEM_ADMIN_USERNAME: ${SYSTEM_ADMIN_USERNAME:?SYSTEM_ADMIN_USERNAME is required}SYSTEM_ADMIN_PASSWORD: ${SYSTEM_ADMIN_PASSWORD:?SYSTEM_ADMIN_PASSWORD is required}SESSION_SECRET: ${SESSION_SECRET:?SESSION_SECRET is required}COOKIE_NAMESPACE: ${COOKIE_NAMESPACE:-}ENCRYPTION_KEY: ${ENCRYPTION_KEY:?ENCRYPTION_KEY is required}WORKFLOW_CREDENTIAL_ENCRYPTION_KEY: ${WORKFLOW_CREDENTIAL_ENCRYPTION_KEY:?WORKFLOW_CREDENTIAL_ENCRYPTION_KEY is required}INTERNAL_API_TOKEN: ${INTERNAL_API_TOKEN:?INTERNAL_API_TOKEN is required}AI_ENCRYPTION_KEY: ${AI_ENCRYPTION_KEY:?AI_ENCRYPTION_KEY is required}MFA_ENCRYPTION_KEY: ${MFA_ENCRYPTION_KEY:?MFA_ENCRYPTION_KEY is required}SSO_ENCRYPTION_KEY: ${SSO_ENCRYPTION_KEY:?SSO_ENCRYPTION_KEY is required}DATA_SOURCE_ENCRYPTION_KEY: ${DATA_SOURCE_ENCRYPTION_KEY:?DATA_SOURCE_ENCRYPTION_KEY is required}PUBLISHER_CREDENTIAL_ENCRYPTION_KEY: ${PUBLISHER_CREDENTIAL_ENCRYPTION_KEY:?PUBLISHER_CREDENTIAL_ENCRYPTION_KEY is required}PUBLISHER_PRIVATE_TARGETS: ${PUBLISHER_PRIVATE_TARGETS:-}EMAIL_ENCRYPTION_KEY: ${EMAIL_ENCRYPTION_KEY:?EMAIL_ENCRYPTION_KEY is required}ADDRESS_PROVIDER_ENCRYPTION_KEY: ${ADDRESS_PROVIDER_ENCRYPTION_KEY:?ADDRESS_PROVIDER_ENCRYPTION_KEY is required}EMAIL_TRACKING_SECRET: ${EMAIL_TRACKING_SECRET:?EMAIL_TRACKING_SECRET is required}PDF_EXPORT_SECRET: ${PDF_EXPORT_SECRET:?PDF_EXPORT_SECRET is required}FORM_FILE_ENCRYPTION_KEYS: ${FORM_FILE_ENCRYPTION_KEYS:?FORM_FILE_ENCRYPTION_KEYS is required}FORM_FILE_ENCRYPTION_ACTIVE_KEY_ID: v1# Optional: Compose omits unset entries from the container environment.# See the commented remote-service example in .env.example.DATA_LAYER_ENABLED:DATA_LAYER_URL:DATA_LAYER_API_KEY:DATA_LAYER_ALLOWED_ENDPOINTS:# Two databases, each with a runtime URL and a separate setup/upgrade owner URL.PGHOST: postgresPGPORT: "5432"PGDATABASE: platformPGUSER: ${PGUSER:-postgres}PGPASSWORD: ${PGPASSWORD:?PGPASSWORD is required}APP_PLATFORM_USER: ${APP_PLATFORM_USER:-app_platform}APP_INTAKE_USER: ${APP_INTAKE_USER:-app_intake}DATABASE_URL: postgresql://${APP_PLATFORM_USER:-app_platform}:${APP_PLATFORM_PASSWORD:?APP_PLATFORM_PASSWORD is required}@postgres:5432/platformINTAKE_DATABASE_URL: postgresql://${APP_INTAKE_USER:-app_intake}:${APP_INTAKE_PASSWORD:?APP_INTAKE_PASSWORD is required}@postgres:5432/intakeAPP_PLATFORM_PASSWORD: ${APP_PLATFORM_PASSWORD:?APP_PLATFORM_PASSWORD is required}APP_INTAKE_PASSWORD: ${APP_INTAKE_PASSWORD:?APP_INTAKE_PASSWORD is required}MIGRATION_PLATFORM_DATABASE_URL: postgresql://${PGUSER:-postgres}:${PGPASSWORD:?PGPASSWORD is required}@postgres:5432/platformMIGRATION_INTAKE_DATABASE_URL: postgresql://${PGUSER:-postgres}:${PGPASSWORD:?PGPASSWORD is required}@postgres:5432/intakeAPP_DB_ROLE: "true"DB_POOL_MAX: "40"SESSION_STORE: redisREDIS_REQUIRED: "true"REDIS_HOST: redisREDIS_PORT: "6379"REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required}SEAWEEDFS_MASTER_URL: http://seaweedfs:9333SEAWEEDFS_FILER_URL: http://seaweedfs:8888SEAWEEDFS_VOLUME_URL: http://seaweedfs:8080ports:- "${HTTP_BIND_ADDRESS:-127.0.0.1}:${HOST_PORT:-3000}:3000"volumes:- "${UPLOADS_DATA:-uploads-data}:/app/uploads"depends_on:postgres:condition: service_healthyredis:condition: service_healthyseaweedfs:condition: service_healthyhealthcheck:test:- CMD- node- -e- "fetch('http://127.0.0.1:3000/api/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"interval: 15stimeout: 5sretries: 3start_period: 120snetworks:- edge- backendpostgres:image: ${POSTGRES_IMAGE:-postgres:17-alpine}restart: unless-stoppedenvironment:POSTGRES_DB: platformPOSTGRES_USER: ${PGUSER:-postgres}POSTGRES_PASSWORD: ${PGPASSWORD:?PGPASSWORD is required}command: ["postgres", "-c", "max_connections=200"]volumes:- "${POSTGRES_DATA:-postgres-data}:/var/lib/postgresql/data"healthcheck:test: ['CMD-SHELL', 'pg_isready -U "$${POSTGRES_USER}" -d "$${POSTGRES_DB}"']interval: 10stimeout: 5sretries: 12start_period: 30snetworks:- backendredis:image: redis:7-alpinerestart: unless-stoppedenvironment:REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required}command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD:?REDIS_PASSWORD is required}"]volumes:- "${REDIS_DATA:-redis-data}:/data"healthcheck:test: ["CMD-SHELL", "REDISCLI_AUTH=\"$${REDIS_PASSWORD}\" redis-cli ping | grep -q PONG"]interval: 10stimeout: 5sretries: 12start_period: 10snetworks:- backend# Master, volume server and filer together for a single-server installation.seaweedfs:image: chrislusf/seaweedfs:4.47restart: unless-stoppedworking_dir: /datacommand:- server- -ip=seaweedfs- -ip.bind=0.0.0.0- -dir=/data- -master.volumeSizeLimitMB=1024- -volume.max=0- -filervolumes:- "${SEAWEEDFS_DATA:-seaweedfs-data}:/data"configs:- source: filertarget: /etc/seaweedfs/filer.tomlhealthcheck:test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:9333/cluster/status && wget -q -O /dev/null http://127.0.0.1:8888/"]interval: 10stimeout: 5sretries: 12start_period: 30snetworks:- backendvolumes:postgres-data:redis-data:uploads-data:seaweedfs-data:networks:edge:backend:internal: trueconfigs:filer:content: |# Persist the file directory/index alongside the file contents in the data volume.[leveldb2]enabled = truedir = "/data/filerldb2"HTTPS: copy and merge the Compose configuration
Paste the base configuration first:
compose.yaml # Lunar Paper with official PostgreSQL. Select the platform version in your private environment.# Initialize or upgrade application schemas explicitly through protected web setup.services:lunarpaper:image: ${LUNAR_PAPER_IMAGE:-ghcr.io/lunarpaper/platform}:${LUNAR_PAPER_VERSION:?LUNAR_PAPER_VERSION is required}restart: unless-stoppedenvironment:NODE_ENV: productionPORT: "3000"PROCESS_ROLE: allCLUSTER_WORKERS: "1"# One browser URL controls origins and cookie security for HTTP or HTTPS.APP_URL: ${APP_URL:?APP_URL is required}API_URL: ${APP_URL:?APP_URL is required}ALLOWED_ORIGINS: ${APP_URL:?APP_URL is required}PUBLISHER_CALLBACK_ORIGINS: ${APP_URL:?APP_URL is required}# Keyed web setup and manual upgrades are fixed application behaviour.SETUP_KEY: ${SETUP_KEY:?SETUP_KEY is required}# Forward the same image selection to the app's release checks.LUNAR_PAPER_IMAGE: ${LUNAR_PAPER_IMAGE:-ghcr.io/lunarpaper/platform}:${LUNAR_PAPER_VERSION:?LUNAR_PAPER_VERSION is required}SYSTEM_ADMIN_USERNAME: ${SYSTEM_ADMIN_USERNAME:?SYSTEM_ADMIN_USERNAME is required}SYSTEM_ADMIN_PASSWORD: ${SYSTEM_ADMIN_PASSWORD:?SYSTEM_ADMIN_PASSWORD is required}SESSION_SECRET: ${SESSION_SECRET:?SESSION_SECRET is required}COOKIE_NAMESPACE: ${COOKIE_NAMESPACE:-}ENCRYPTION_KEY: ${ENCRYPTION_KEY:?ENCRYPTION_KEY is required}WORKFLOW_CREDENTIAL_ENCRYPTION_KEY: ${WORKFLOW_CREDENTIAL_ENCRYPTION_KEY:?WORKFLOW_CREDENTIAL_ENCRYPTION_KEY is required}INTERNAL_API_TOKEN: ${INTERNAL_API_TOKEN:?INTERNAL_API_TOKEN is required}AI_ENCRYPTION_KEY: ${AI_ENCRYPTION_KEY:?AI_ENCRYPTION_KEY is required}MFA_ENCRYPTION_KEY: ${MFA_ENCRYPTION_KEY:?MFA_ENCRYPTION_KEY is required}SSO_ENCRYPTION_KEY: ${SSO_ENCRYPTION_KEY:?SSO_ENCRYPTION_KEY is required}DATA_SOURCE_ENCRYPTION_KEY: ${DATA_SOURCE_ENCRYPTION_KEY:?DATA_SOURCE_ENCRYPTION_KEY is required}PUBLISHER_CREDENTIAL_ENCRYPTION_KEY: ${PUBLISHER_CREDENTIAL_ENCRYPTION_KEY:?PUBLISHER_CREDENTIAL_ENCRYPTION_KEY is required}PUBLISHER_PRIVATE_TARGETS: ${PUBLISHER_PRIVATE_TARGETS:-}EMAIL_ENCRYPTION_KEY: ${EMAIL_ENCRYPTION_KEY:?EMAIL_ENCRYPTION_KEY is required}ADDRESS_PROVIDER_ENCRYPTION_KEY: ${ADDRESS_PROVIDER_ENCRYPTION_KEY:?ADDRESS_PROVIDER_ENCRYPTION_KEY is required}EMAIL_TRACKING_SECRET: ${EMAIL_TRACKING_SECRET:?EMAIL_TRACKING_SECRET is required}PDF_EXPORT_SECRET: ${PDF_EXPORT_SECRET:?PDF_EXPORT_SECRET is required}FORM_FILE_ENCRYPTION_KEYS: ${FORM_FILE_ENCRYPTION_KEYS:?FORM_FILE_ENCRYPTION_KEYS is required}FORM_FILE_ENCRYPTION_ACTIVE_KEY_ID: v1# Optional: Compose omits unset entries from the container environment.# See the commented remote-service example in .env.example.DATA_LAYER_ENABLED:DATA_LAYER_URL:DATA_LAYER_API_KEY:DATA_LAYER_ALLOWED_ENDPOINTS:# Two databases, each with a runtime URL and a separate setup/upgrade owner URL.PGHOST: postgresPGPORT: "5432"PGDATABASE: platformPGUSER: ${PGUSER:-postgres}PGPASSWORD: ${PGPASSWORD:?PGPASSWORD is required}APP_PLATFORM_USER: ${APP_PLATFORM_USER:-app_platform}APP_INTAKE_USER: ${APP_INTAKE_USER:-app_intake}DATABASE_URL: postgresql://${APP_PLATFORM_USER:-app_platform}:${APP_PLATFORM_PASSWORD:?APP_PLATFORM_PASSWORD is required}@postgres:5432/platformINTAKE_DATABASE_URL: postgresql://${APP_INTAKE_USER:-app_intake}:${APP_INTAKE_PASSWORD:?APP_INTAKE_PASSWORD is required}@postgres:5432/intakeAPP_PLATFORM_PASSWORD: ${APP_PLATFORM_PASSWORD:?APP_PLATFORM_PASSWORD is required}APP_INTAKE_PASSWORD: ${APP_INTAKE_PASSWORD:?APP_INTAKE_PASSWORD is required}MIGRATION_PLATFORM_DATABASE_URL: postgresql://${PGUSER:-postgres}:${PGPASSWORD:?PGPASSWORD is required}@postgres:5432/platformMIGRATION_INTAKE_DATABASE_URL: postgresql://${PGUSER:-postgres}:${PGPASSWORD:?PGPASSWORD is required}@postgres:5432/intakeAPP_DB_ROLE: "true"DB_POOL_MAX: "40"SESSION_STORE: redisREDIS_REQUIRED: "true"REDIS_HOST: redisREDIS_PORT: "6379"REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required}SEAWEEDFS_MASTER_URL: http://seaweedfs:9333SEAWEEDFS_FILER_URL: http://seaweedfs:8888SEAWEEDFS_VOLUME_URL: http://seaweedfs:8080volumes:- "${UPLOADS_DATA:-uploads-data}:/app/uploads"depends_on:postgres:condition: service_healthyredis:condition: service_healthyseaweedfs:condition: service_healthyhealthcheck:test:- CMD- node- -e- "fetch('http://127.0.0.1:3000/api/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"interval: 15stimeout: 5sretries: 3start_period: 120snetworks:- edge- backendpostgres:image: ${POSTGRES_IMAGE:-postgres:17-alpine}restart: unless-stoppedenvironment:POSTGRES_DB: platformPOSTGRES_USER: ${PGUSER:-postgres}POSTGRES_PASSWORD: ${PGPASSWORD:?PGPASSWORD is required}command: ["postgres", "-c", "max_connections=200"]volumes:- "${POSTGRES_DATA:-postgres-data}:/var/lib/postgresql/data"healthcheck:test: ['CMD-SHELL', 'pg_isready -U "$${POSTGRES_USER}" -d "$${POSTGRES_DB}"']interval: 10stimeout: 5sretries: 12start_period: 30snetworks:- backendredis:image: redis:7-alpinerestart: unless-stoppedenvironment:REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required}command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD:?REDIS_PASSWORD is required}"]volumes:- "${REDIS_DATA:-redis-data}:/data"healthcheck:test: ["CMD-SHELL", "REDISCLI_AUTH=\"$${REDIS_PASSWORD}\" redis-cli ping | grep -q PONG"]interval: 10stimeout: 5sretries: 12start_period: 10snetworks:- backend# Master, volume server and filer together for a single-server installation.seaweedfs:image: chrislusf/seaweedfs:4.47restart: unless-stoppedworking_dir: /datacommand:- server- -ip=seaweedfs- -ip.bind=0.0.0.0- -dir=/data- -master.volumeSizeLimitMB=1024- -volume.max=0- -filervolumes:- "${SEAWEEDFS_DATA:-seaweedfs-data}:/data"- ./filer.toml:/etc/seaweedfs/filer.toml:rohealthcheck:test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:9333/cluster/status && wget -q -O /dev/null http://127.0.0.1:8888/"]interval: 10stimeout: 5sretries: 12start_period: 30snetworks:- backendvolumes:postgres-data:redis-data:uploads-data:seaweedfs-data:networks:edge:backend:internal: trueSet
TRUST_PROXY_HOPS: "1"in the existinglunarpaperenvironment. Add thecaddyservice and its two volumes from this HTTPS configuration to the existingservices:andvolumes:sections. Do not duplicate top-level keys or add the HTTP port mapping. Create the supporting files in step 5.HTTPS settings to merge # Use with compose.yaml; set APP_URL to https://your-internal-hostname.services:lunarpaper:environment:TRUST_PROXY_HOPS: "1"caddy:image: caddy:2-alpinerestart: unless-stoppedenvironment:APP_URL: ${APP_URL:?APP_URL is required}CADDY_TLS_DIRECTIVE: ${CADDY_TLS_DIRECTIVE-tls internal}ports:- "80:80"- "443:443"- "443:443/udp"volumes:- ./Caddyfile:/etc/caddy/Caddyfile:ro- caddy-data:/data- caddy-config:/configdepends_on:lunarpaper:condition: service_healthynetworks:- edgevolumes:caddy-data:caddy-config: -
Add your settings. In the Environment (.env) editor, paste these settings, replace the example addresses and administrator details, then paste the generated lines from step 1 below them.
LUNAR_PAPER_VERSION=0.8.1# Optional image repository override, without a tag.# LUNAR_PAPER_IMAGE=ghcr.io/lunarpaper/platform# Optional cookie isolation for another instance on the same hostname.# COOKIE_NAMESPACE=lunarpaper_testAPP_URL=http://192.168.1.20:3000HTTP_BIND_ADDRESS=192.168.1.20HOST_PORT=3000PGUSER=postgresAPP_PLATFORM_USER=app_platformAPP_INTAKE_USER=app_intakePOSTGRES_DATA=postgres-dataREDIS_DATA=redis-dataUPLOADS_DATA=uploads-dataSEAWEEDFS_DATA=seaweedfs-dataSYSTEM_ADMIN_USERNAME=you@example.comSYSTEM_ADMIN_PASSWORD=replace-with-your-passwordLUNAR_PAPER_VERSION=0.8.1# Optional image repository override, without a tag.# LUNAR_PAPER_IMAGE=ghcr.io/lunarpaper/platform# Optional cookie isolation for another instance on the same hostname.# COOKIE_NAMESPACE=lunarpaper_testAPP_URL=https://paper.internalPGUSER=postgresAPP_PLATFORM_USER=app_platformAPP_INTAKE_USER=app_intakePOSTGRES_DATA=postgres-dataREDIS_DATA=redis-dataUPLOADS_DATA=uploads-dataSEAWEEDFS_DATA=seaweedfs-dataSYSTEM_ADMIN_USERNAME=you@example.comSYSTEM_ADMIN_PASSWORD=replace-with-your-passwordCADDY_TLS_DIRECTIVE=tls internalFor a public domain, use
tls you@example.com.For HTTP, replace
192.168.1.20with an IP actually assigned to your Arcane server.HOST_PORTselects the host port; include it inAPP_URL. For access only from the server itself, useHTTP_BIND_ADDRESS=127.0.0.1andAPP_URL=http://localhost:3000.APP_URLmust match the browser address exactly. The password needs 12 or more characters, with upper case, lower case, a number and a symbol, and no spaces or quotes.Database usernames have defaults above. You can override them before first setup; see Database usernames for naming rules and existing-installation limits.
-
Create the HTTPS supporting files. Skip this step for HTTP.
HTTPS: create filer.toml and Caddyfile
Create these two files in the project workspace before starting. Keep their names and relative mount paths unchanged.
filer.toml # Persist the file directory/index alongside the file contents in the data volume.[leveldb2]enabled = truedir = "/data/filerldb2"Caddyfile {$APP_URL} {{$CADDY_TLS_DIRECTIVE}encode zstd gzipreverse_proxy lunarpaper:3000header -Server} -
Create and start the project. Select Create Project. If the project does not start by itself, select Up. Wait until
lunarpaper,postgres,redisandseaweedfsshow as healthy on the Services tab. Database health confirms that PostgreSQL is running; keyed setup still needs working owner credentials. -
Trust the certificate. You only need this step for HTTPS with an internal name. On the server, run:
Terminal window docker cp lunarpaper-caddy-1:/data/caddy/pki/authorities/local/root.crt lunarpaper-root.crtFor a custom project name, use the Caddy container name shown in Arcane. Then install it on each device, as in the certificate step of the HTTPS guide.
-
Open your
APP_URLand initialize. Unlock setup withSETUP_KEY, review the empty databases and explicitly start initialization. Wait for Platform, Intake and release activation to verify, then launch and sign in. See First-time setup.
If you see a maintenance page instead, follow Complete the database upgrade.
The project’s .env holds the keys that decrypt your data, and every Arcane
administrator can read it. Keep the copy you saved in step 1 with your backups.
Upgrade
Section titled “Upgrade”- Take a backup.
- Read the release notes. In Configuration, change
LUNAR_PAPER_VERSIONin Environment (.env) to the new published version. KeepLUNAR_PAPER_IMAGEas the repository name without a tag; Compose appends the version. Keep the project’s name, access settings, secrets and volume identities. - Pull the new platform image and redeploy the
lunarpaperservice. Keep the PostgreSQL image unchanged; updating its engine is a separate operation. Review any Compose changes called out in the release notes before redeploying. - If a maintenance page appears, complete the database upgrade.
Troubleshooting
Section titled “Troubleshooting”- Database login fails with
28P01. The storage may belong to an earlier installation with different passwords. Restore its original settings or use a separate project and storage for a fresh installation. Do not regenerate secrets against retained volumes. - Your changes have no effect. Select Redeploy to apply them.
- A service keeps restarting. Read its log on the Services tab. The usual cause is a password that breaks the rules, or a missing value.
- The project shows “Partially running”. An older project may have a
database-bootstrapservice. Those pre-public deployment files need a separate upgrade review; do not delete their data volumes. See Older development deployments. - Another Lunar Paper project runs on this server. Each project needs its own project name and its own ports. See More than one instance.
- An HTTPS file mount fails. Create
filer.tomlandCaddyfileas files in the project workspace before starting. The HTTP example embeds its storage config.
Backups work the same way as for Docker
Compose. Use the effective Arcane project name when identifying volumes; do not
assume every project uses the lunarpaper_ prefix.
