Install with docker run
This guide is for a quick trial. Select a Lunar Paper version, then start it
with official PostgreSQL using docker run. It starts four containers: lunarpaper-postgres,
lunarpaper-redis, lunarpaper-seaweedfs, and lunarpaper, which serves
Lunar Paper on host port 3000 by default. You can choose another host port.
Before you start
Section titled “Before you start”- Install Docker and open a terminal (PowerShell on Windows).
- Choose an unused host port. The example uses 3000; you can change it.
- Choose a published platform release. These examples target 0.8.1 in lunarpaper/lunarpaper. Its public image must be published before it can be pulled.
- Linux and macOS need OpenSSL to generate secrets.
Create a working folder and run the remaining commands from it:
mkdir lunarpapercd lunarpaperUse a different port
Section titled “Use a different port”Set HOST_PORT and include the same port in APP_URL in step 1. For example,
use HOST_PORT=3100 with APP_URL=http://localhost:3100. The commands map this
host port to the application’s fixed container port 3000.
HTTP_BIND_ADDRESS defaults to 127.0.0.1 for access from this computer only.
For LAN access, set it to an IP actually assigned to the server and use that
address in APP_URL. Changing APP_URL alone does not change the port or interface.
Running multiple instances
For a second fresh instance, use the
Compose multiple-instance instructions.
These docker run commands use fixed container, network and volume names.
COMPOSE_PROJECT_NAME does not affect docker run; changing only the folder or
host port does not separate its storage.
The volumes also use the main Compose guide’s default lunarpaper_ prefix to
support the migration instructions below. Do not run this fresh-install path
against an existing installation’s volumes. Retained PostgreSQL volumes keep
their original passwords even after containers are removed. Restore the saved
settings for an existing installation; generate new secrets only for empty storage.
Install
Section titled “Install”-
Set your configuration. Edit the address and administrator details, then paste this into your terminal.
Terminal window export LUNAR_PAPER_VERSION=0.8.1export LUNAR_PAPER_IMAGE="ghcr.io/lunarpaper/platform"export POSTGRES_IMAGE=postgres:17-alpineexport PGUSER=postgresexport APP_PLATFORM_USER=app_platformexport APP_INTAKE_USER=app_intakeexport APP_URL=http://localhost:3000export HOST_PORT=3000export HTTP_BIND_ADDRESS=127.0.0.1export COOKIE_NAMESPACE=export SYSTEM_ADMIN_USERNAME=you@example.comexport SYSTEM_ADMIN_PASSWORD='replace-with-your-password'Terminal window $env:LUNAR_PAPER_VERSION = '0.8.1'$env:LUNAR_PAPER_IMAGE = "ghcr.io/lunarpaper/platform"$env:POSTGRES_IMAGE = 'postgres:17-alpine'$env:PGUSER = 'postgres'$env:APP_PLATFORM_USER = 'app_platform'$env:APP_INTAKE_USER = 'app_intake'$env:APP_URL = 'http://localhost:3000'$env:HOST_PORT = '3000'$env:HTTP_BIND_ADDRESS = '127.0.0.1'$env:COOKIE_NAMESPACE = ''$env:SYSTEM_ADMIN_USERNAME = 'you@example.com'$env:SYSTEM_ADMIN_PASSWORD = 'replace-with-your-password'APP_URLis the address you open in the browser. An address withlocalhostonly works on this computer. The password needs 12 or more characters, with upper case, lower case, a number and a symbol, and no spaces or quotes.PGUSERdefaults topostgresand names the owner used for setup and upgrades. Choose it before creating the PostgreSQL volume. Use lowercase letters, numbers and underscores; avoidapp_*,pg_*,svc_datalayerandreporting. The application usernames also have defaults that you can override before setup. See Database usernames for naming rules. Every database password is independently generated. -
Generate new secrets in the same terminal. For an existing installation, restore its saved settings instead; new passwords do not update existing databases.
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; doexport "$name=$(openssl rand -hex 32)"doneexport 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') {[Environment]::SetEnvironmentVariable($n, (New-Hex))}$env:FORM_FILE_ENCRYPTION_KEYS = '{"v1":"' + (New-Hex) + '"}' -
Save your settings. Copy this command’s output into a password manager. It contains all your secrets.
Terminal window for name in LUNAR_PAPER_VERSION LUNAR_PAPER_IMAGE POSTGRES_IMAGE PGUSER APP_PLATFORM_USER APP_INTAKE_USER APP_URL HOST_PORT HTTP_BIND_ADDRESS COOKIE_NAMESPACE SYSTEM_ADMIN_USERNAME SYSTEM_ADMIN_PASSWORD \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 FORM_FILE_ENCRYPTION_KEYS; doprintf "export %s='%s'\n" "$name" "$(printenv "$name")"doneTerminal window foreach ($n in 'LUNAR_PAPER_VERSION', 'LUNAR_PAPER_IMAGE', 'POSTGRES_IMAGE', 'PGUSER', 'APP_PLATFORM_USER', 'APP_INTAKE_USER', 'APP_URL', 'HOST_PORT', 'HTTP_BIND_ADDRESS', 'COOKIE_NAMESPACE', 'SYSTEM_ADMIN_USERNAME', 'SYSTEM_ADMIN_PASSWORD','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', 'FORM_FILE_ENCRYPTION_KEYS') {"`$env:$n = '$([Environment]::GetEnvironmentVariable($n))'"}Restore this block in each new terminal and before upgrades. It preserves your image versions, address, port, usernames and secrets.
-
Create the network.
Terminal window docker network create lunarpaper -
Start the database.
Terminal window docker run -d --name lunarpaper-postgres --network lunarpaper --network-alias postgres \--restart unless-stopped \-e POSTGRES_DB=platform -e POSTGRES_USER="$PGUSER" -e POSTGRES_PASSWORD="$PGPASSWORD" \--health-cmd='pg_isready -U $POSTGRES_USER -d platform' --health-interval=5s --health-retries=12 \-v lunarpaper_postgres-data:/var/lib/postgresql/data \"$POSTGRES_IMAGE" postgres -c max_connections=200Terminal window docker run -d --name lunarpaper-postgres --network lunarpaper --network-alias postgres `--restart unless-stopped `-e POSTGRES_DB=platform -e "POSTGRES_USER=$env:PGUSER" -e "POSTGRES_PASSWORD=$env:PGPASSWORD" `--health-cmd='pg_isready -U $POSTGRES_USER -d platform' --health-interval=5s --health-retries=12 `-v lunarpaper_postgres-data:/var/lib/postgresql/data `"$env:POSTGRES_IMAGE" postgres -c max_connections=200 -
Start Redis and file storage.
Create
filer.tomlwithnotepad filer.tomlornano filer.tomland paste:Create filer.toml
[leveldb2]enabled = truedir = "/data/filerldb2"Start Redis and SeaweedFS after saving the file:
Terminal window docker run -d --name lunarpaper-redis --network lunarpaper --network-alias redis \--restart unless-stopped -v lunarpaper_redis-data:/data -e REDIS_PASSWORD \redis:7-alpine redis-server --appendonly yes --requirepass "$REDIS_PASSWORD"docker run -d --name lunarpaper-seaweedfs --network lunarpaper --network-alias seaweedfs \--restart unless-stopped -w /data -v lunarpaper_seaweedfs-data:/data \-v "$PWD/filer.toml:/etc/seaweedfs/filer.toml:ro" \chrislusf/seaweedfs:4.47 server -ip=seaweedfs -ip.bind=0.0.0.0 -dir=/data \-master.volumeSizeLimitMB=1024 -volume.max=0 -filerTerminal window docker run -d --name lunarpaper-redis --network lunarpaper --network-alias redis `--restart unless-stopped -v lunarpaper_redis-data:/data -e REDIS_PASSWORD `redis:7-alpine redis-server --appendonly yes --requirepass $env:REDIS_PASSWORDdocker run -d --name lunarpaper-seaweedfs --network lunarpaper --network-alias seaweedfs `--restart unless-stopped -w /data -v lunarpaper_seaweedfs-data:/data `-v "${PWD}/filer.toml:/etc/seaweedfs/filer.toml:ro" `chrislusf/seaweedfs:4.47 server -ip=seaweedfs -ip.bind=0.0.0.0 -dir=/data `-master.volumeSizeLimitMB=1024 -volume.max=0 -filer -
Start Lunar Paper. The first line waits until the database is ready.
Terminal window until [ "$(docker inspect -f '{{.State.Health.Status}}' lunarpaper-postgres)" = healthy ]; do sleep 2; donedocker run -d --name lunarpaper --network lunarpaper --restart unless-stopped \-p "${HTTP_BIND_ADDRESS}:${HOST_PORT}:3000" -v lunarpaper_uploads-data:/app/uploads \-e NODE_ENV=production -e PORT=3000 -e PROCESS_ROLE=all -e CLUSTER_WORKERS=1 -e TRUST_PROXY_HOPS=0 \-e APP_URL -e API_URL="$APP_URL" -e ALLOWED_ORIGINS="$APP_URL" -e PUBLISHER_CALLBACK_ORIGINS="$APP_URL" \-e LUNAR_PAPER_IMAGE="${LUNAR_PAPER_IMAGE}:${LUNAR_PAPER_VERSION}" \-e SETUP_KEY -e SYSTEM_ADMIN_USERNAME -e SYSTEM_ADMIN_PASSWORD \-e APP_PLATFORM_PASSWORD -e APP_INTAKE_PASSWORD \-e PUBLISHER_PRIVATE_TARGETS -e COOKIE_NAMESPACE \-e SESSION_SECRET -e ENCRYPTION_KEY -e INTERNAL_API_TOKEN -e AI_ENCRYPTION_KEY -e MFA_ENCRYPTION_KEY \-e SSO_ENCRYPTION_KEY -e DATA_SOURCE_ENCRYPTION_KEY -e WORKFLOW_CREDENTIAL_ENCRYPTION_KEY \-e PUBLISHER_CREDENTIAL_ENCRYPTION_KEY -e EMAIL_ENCRYPTION_KEY -e ADDRESS_PROVIDER_ENCRYPTION_KEY \-e EMAIL_TRACKING_SECRET -e PDF_EXPORT_SECRET \-e FORM_FILE_ENCRYPTION_KEYS -e FORM_FILE_ENCRYPTION_ACTIVE_KEY_ID=v1 \-e PGHOST=postgres -e PGPORT=5432 -e PGDATABASE=platform -e PGUSER -e PGPASSWORD -e APP_PLATFORM_USER -e APP_INTAKE_USER \-e DATABASE_URL="postgresql://${APP_PLATFORM_USER}:$APP_PLATFORM_PASSWORD@postgres:5432/platform" \-e INTAKE_DATABASE_URL="postgresql://${APP_INTAKE_USER}:$APP_INTAKE_PASSWORD@postgres:5432/intake" \-e MIGRATION_PLATFORM_DATABASE_URL="postgresql://${PGUSER}:$PGPASSWORD@postgres:5432/platform" \-e MIGRATION_INTAKE_DATABASE_URL="postgresql://${PGUSER}:$PGPASSWORD@postgres:5432/intake" \-e APP_DB_ROLE=true -e DB_POOL_MAX=40 \-e SESSION_STORE=redis -e REDIS_REQUIRED=true -e REDIS_HOST=redis -e REDIS_PORT=6379 -e REDIS_PASSWORD \-e SEAWEEDFS_MASTER_URL=http://seaweedfs:9333 -e SEAWEEDFS_FILER_URL=http://seaweedfs:8888 \-e SEAWEEDFS_VOLUME_URL=http://seaweedfs:8080 \"${LUNAR_PAPER_IMAGE}:${LUNAR_PAPER_VERSION}"Terminal window while ((docker inspect -f '{{.State.Health.Status}}' lunarpaper-postgres) -ne 'healthy') { Start-Sleep -Seconds 2 }docker run -d --name lunarpaper --network lunarpaper --restart unless-stopped `-p "${env:HTTP_BIND_ADDRESS}:${env:HOST_PORT}:3000" -v lunarpaper_uploads-data:/app/uploads `-e NODE_ENV=production -e PORT=3000 -e PROCESS_ROLE=all -e CLUSTER_WORKERS=1 -e TRUST_PROXY_HOPS=0 `-e APP_URL -e "API_URL=$env:APP_URL" -e "ALLOWED_ORIGINS=$env:APP_URL" -e "PUBLISHER_CALLBACK_ORIGINS=$env:APP_URL" `-e "LUNAR_PAPER_IMAGE=${env:LUNAR_PAPER_IMAGE}:${env:LUNAR_PAPER_VERSION}" `-e SETUP_KEY -e SYSTEM_ADMIN_USERNAME -e SYSTEM_ADMIN_PASSWORD `-e APP_PLATFORM_PASSWORD -e APP_INTAKE_PASSWORD `-e PUBLISHER_PRIVATE_TARGETS -e COOKIE_NAMESPACE `-e SESSION_SECRET -e ENCRYPTION_KEY -e INTERNAL_API_TOKEN -e AI_ENCRYPTION_KEY -e MFA_ENCRYPTION_KEY `-e SSO_ENCRYPTION_KEY -e DATA_SOURCE_ENCRYPTION_KEY -e WORKFLOW_CREDENTIAL_ENCRYPTION_KEY `-e PUBLISHER_CREDENTIAL_ENCRYPTION_KEY -e EMAIL_ENCRYPTION_KEY -e ADDRESS_PROVIDER_ENCRYPTION_KEY `-e EMAIL_TRACKING_SECRET -e PDF_EXPORT_SECRET `-e FORM_FILE_ENCRYPTION_KEYS -e FORM_FILE_ENCRYPTION_ACTIVE_KEY_ID=v1 `-e PGHOST=postgres -e PGPORT=5432 -e PGDATABASE=platform -e PGUSER -e PGPASSWORD -e APP_PLATFORM_USER -e APP_INTAKE_USER `-e "DATABASE_URL=postgresql://$($env:APP_PLATFORM_USER):$($env:APP_PLATFORM_PASSWORD)@postgres:5432/platform" `-e "INTAKE_DATABASE_URL=postgresql://$($env:APP_INTAKE_USER):$($env:APP_INTAKE_PASSWORD)@postgres:5432/intake" `-e "MIGRATION_PLATFORM_DATABASE_URL=postgresql://$($env:PGUSER):$($env:PGPASSWORD)@postgres:5432/platform" `-e "MIGRATION_INTAKE_DATABASE_URL=postgresql://$($env:PGUSER):$($env:PGPASSWORD)@postgres:5432/intake" `-e APP_DB_ROLE=true -e DB_POOL_MAX=40 `-e SESSION_STORE=redis -e REDIS_REQUIRED=true -e REDIS_HOST=redis -e REDIS_PORT=6379 -e REDIS_PASSWORD `-e SEAWEEDFS_MASTER_URL=http://seaweedfs:9333 -e SEAWEEDFS_FILER_URL=http://seaweedfs:8888 `-e SEAWEEDFS_VOLUME_URL=http://seaweedfs:8080 `"${env:LUNAR_PAPER_IMAGE}:${env:LUNAR_PAPER_VERSION}" -
Open your
APP_URLand initialize. Unlock setup withSETUP_KEY, review the empty databases and explicitly start initialization. The platform imports its bundled init files and verifies Platform, Intake and release activation. Launch the application after completion, then sign in. See First-time setup.
If you see a maintenance page instead, follow Complete the database upgrade.
Check that it is running
Section titled “Check that it is running”All four containers should show Up, and lunarpaper-postgres and
lunarpaper should also show (healthy):
docker ps --filter name=lunarpaperWatch the log; press Ctrl+C to stop:
docker logs -f lunarpaperLunar Paper is ready when this returns HTTP 200. If you chose a different host port, replace 3000 in these URLs with that port:
curl -fsS http://localhost:3000/api/health/ready(Invoke-WebRequest -UseBasicParsing http://localhost:3000/api/health/ready).StatusCodeUse it from another computer
Section titled “Use it from another computer”-
Paste your saved block, then set
APP_URLto this computer’s network address:Terminal window export HTTP_BIND_ADDRESS=192.168.1.20export APP_URL="http://${HTTP_BIND_ADDRESS}:${HOST_PORT}"Terminal window $env:HTTP_BIND_ADDRESS = '192.168.1.20'$env:APP_URL = "http://${env:HTTP_BIND_ADDRESS}:${env:HOST_PORT}"Replace
192.168.1.20with an IP actually assigned to your server. -
Remove the
lunarpapercontainer, then run step 7 again. Your data is not affected.Terminal window docker rm -f lunarpaper -
Run step 3 again and save the new block, because
APP_URLhas changed.
For firewall settings and the limits of HTTP, see HTTP on a local network.
Stop and start Lunar Paper
Section titled “Stop and start Lunar Paper”The containers start again whenever Docker starts, unless you stop them. To stop Lunar Paper:
docker stop lunarpaper lunarpaper-seaweedfs lunarpaper-redis lunarpaper-postgresTo start it again:
docker start lunarpaper-postgres lunarpaper-redis lunarpaper-seaweedfs lunarpaperUpgrade
Section titled “Upgrade”-
Read the release notes and paste your saved settings block. Change
LUNAR_PAPER_VERSIONto the new published version. KeepLUNAR_PAPER_IMAGEas the repository name without a tag. Preserve all secrets and your chosen host port. Keep PostgreSQL on its existing image. -
Pull the new platform image, then remove only the application container. Your databases and data volumes stay in place.
Terminal window docker pull "${LUNAR_PAPER_IMAGE}:${LUNAR_PAPER_VERSION}"Terminal window docker pull "${env:LUNAR_PAPER_IMAGE}:${env:LUNAR_PAPER_VERSION}"Terminal window docker rm -f lunarpaper -
Run step 7 again to create the platform container with its new image.
-
If a maintenance page appears, complete the database upgrade.
-
Run step 3 of the installation again to save your updated settings block.
Move to Docker Compose
Section titled “Move to Docker Compose”Docker Compose uses the same volumes as these commands, so your data moves with you.
-
Create a
lunarpaperfolder and createcompose.yamlfrom step 4 of the Docker Compose guide. -
Open a terminal in that folder, paste your saved block, and then run this command to write it to
.envbesidecompose.yaml. Use this only when.envdoes not already exist; never overwrite an existing environment file:Terminal window if [ -e .env ]; then echo 'Stop: .env already exists'; elsefor name in LUNAR_PAPER_VERSION LUNAR_PAPER_IMAGE POSTGRES_IMAGE PGUSER APP_PLATFORM_USER APP_INTAKE_USER APP_URL HOST_PORT HTTP_BIND_ADDRESS COOKIE_NAMESPACE SYSTEM_ADMIN_USERNAME SYSTEM_ADMIN_PASSWORD \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 FORM_FILE_ENCRYPTION_KEYS; doprintf '%s=%s\n' "$name" "$(printenv "$name")"done > .envchmod 600 .envfiTerminal window if (Test-Path .env) { throw 'Stop: .env already exists' }$lines = foreach ($n in 'LUNAR_PAPER_VERSION', 'LUNAR_PAPER_IMAGE', 'POSTGRES_IMAGE', 'PGUSER', 'APP_PLATFORM_USER', 'APP_INTAKE_USER', 'APP_URL', 'HOST_PORT', 'HTTP_BIND_ADDRESS', 'COOKIE_NAMESPACE', 'SYSTEM_ADMIN_USERNAME', 'SYSTEM_ADMIN_PASSWORD','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', 'FORM_FILE_ENCRYPTION_KEYS') {"$n=$([Environment]::GetEnvironmentVariable($n))"}Set-Content -Path .env -Value $lines -Encoding asciiThe saved settings include
HTTP_BIND_ADDRESS,HOST_PORTandCOOKIE_NAMESPACE. Preserve them when moving to Compose. -
Remove the containers and the network. The volumes, which hold your data, are kept.
Terminal window docker rm -f lunarpaper lunarpaper-seaweedfs lunarpaper-redis lunarpaper-postgresdocker network rm lunarpaper -
Start Lunar Paper with Docker Compose:
Terminal window docker compose up -d --waitKeep the project name
lunarpaperso Compose uses the existing volumes. Warnings that the volumes “already exist” are expected.
Remove Lunar Paper
Section titled “Remove Lunar Paper”To remove the containers and the network:
docker rm -f lunarpaper lunarpaper-seaweedfs lunarpaper-redis lunarpaper-postgresdocker network rm lunarpaperYour data stays in the volumes until you delete them.
Troubleshooting
Section titled “Troubleshooting”- Lunar Paper keeps restarting. Run
docker logs lunarpaperto see why. The usual cause is a password that breaks the rules, or a setting that was empty. Paste your saved block, rundocker rm -f lunarpaper, and run step 7 again. - The settings are gone in a new terminal. Settings only last for the terminal you set them in. Paste your saved block again.
- Port 3000 is in use. Set
HOST_PORTto an available port, include it inAPP_URL, and use those settings when creating the application container. - Database login fails with
28P01. Restore the settings that belong to the retained PostgreSQL volume. New environment values do not replace stored passwords. For a fresh parallel installation, use Compose with a new project name. - Sign-in keeps returning to the sign-in page. Make sure the address in your
browser is exactly the same as
APP_URL.127.0.0.1andlocalhostcount as different addresses. - Step 7 never finishes. Press Ctrl+C and run
docker logs lunarpaper-postgresto see why the database did not start. - An image download fails. Check that the release is published and that
LUNAR_PAPER_IMAGEis the repository without a tag andLUNAR_PAPER_VERSIONis the published version selected in step 1. Official PostgreSQL has an independent version; it never uses a Lunar Paper release tag.
