I had Papra running on my NAS before I had a working account. The container started, all 18 database migrations completed, and the registration form still failed with “Failed to create user.”
The SQLite file belonged to root. Papra never surfaced that detail in the browser, so the fifth installation step is fixing ownership after the first start.
The directories
SSH into your NAS and create the working directories:
mkdir -p /volume1/docker/papra/app-data/db
mkdir -p /volume1/documents
The db directory holds the SQLite database. Documents live separately at /volume1/documents so they survive container recreation.
The Compose file
Generate an auth secret first:
openssl rand -hex 32
Then write the compose file:
cat > /volume1/docker/papra/docker-compose.yml << 'EOF'
services:
papra:
container_name: papra
image: ghcr.io/papra-hq/papra:latest
restart: unless-stopped
ports:
- "1221:1221"
environment:
- AUTH_SECRET=<your-generated-secret>
- APP_BASE_URL=http://<your-nas-hostname>:1221
volumes:
- ./app-data/db:/app/app-data/db
- /volume1/documents:/app/app-data/documents
user: "1000:1000"
EOF
Replace <your-generated-secret> and <your-nas-hostname>. Run id -u && id -g to confirm your actual UID and GID before setting the user field — Synology and UGREEN differ.
APP_BASE_URL must match the URL you use in the browser exactly. A mismatch causes an “Invalid application origin” error on the register page.
First start
cd /volume1/docker/papra && docker compose up -d
Papra runs all database migrations automatically on first start. You’ll see 18 migration entries in the logs, then Server started on port 1221.
The permissions failure
Check SQLite ownership first Registration fails silently if the SQLite database is owned by root. The error in the logs is
SQLITE_READONLY. The error on screen is “Failed to create user” with no explanation.
The first container run may write db.sqlite as root if your UID/GID setup wasn’t right. Fix it with a temporary Alpine container — no sudo required:
docker run --rm \
-v /volume1/docker/papra/app-data:/data \
alpine chown -R 1000:1000 /data
Then restart:
cd /volume1/docker/papra && docker compose restart
Verify before restarting by checking the file owner:
ls -la /volume1/docker/papra/app-data/db/
The db.sqlite file should be owned by your user, not root.
Registration
Go to http://<your-nas-hostname>:1221/register. There are no default credentials. The first account you create is your account.
Upgrades
Papra uses image tags rather than pinned versions, so pulling latest is the upgrade path:
cd /volume1/docker/papra
docker compose pull
docker compose up -d
Compose stops the old container, starts the new one, and migrations run automatically. No manual schema steps. Confirm the new image is running:
docker inspect papra --format '{{.Config.Image}}'
docker logs papra 2>&1 | tail -20
The AUTH_SECRET must stay consistent across upgrades — changing it invalidates all existing sessions.
I hit the same class of host-volume failure while running Hermes Agent on the same NAS. A container can start successfully and still be unusable when its mounted files belong to the wrong user.
One quick signal
Did this earn your time?
Thanks. That gives me something concrete to check.



