Self-hosting

Configuration

Environment variables, volumes, ports and image tags for a self-hosted Inkspace.

Inkspace is configured entirely through environment variables on the two Compose services. Changes made inside a running container are not persistent — keep all configuration in your Compose file.

App service

Variable Required Default Notes
DATABASE_URL Yes — PostgreSQL connection string, e.g. postgresql://inkspace:PASSWORD@db:5432/inkspace.
BETTER_AUTH_URL Yes — Public site URL, e.g. https://stories.example.com. Must match the browser origin.
BETTER_AUTH_SECRET Yes — Long, stable random secret. Changing it can invalidate sessions.
PORT No 6767 Port the app listens on inside the container.
INKSPACE_UPLOAD_DIR No /inkspace/uploads Directory for uploaded images.
INKSPACE_ALLOW_SCHEMA_DATA_LOSS No unset Set to true for one start to let a schema update drop tables or columns. Back up first.

The container refuses to start if DATABASE_URL, BETTER_AUTH_URL or BETTER_AUTH_SECRET is missing.

Generate a secret with:

openssl rand -base64 32

Why BETTER_AUTH_URL matters

Inkspace’s write endpoints — authentication, uploads, import and error logging — reject requests whose Origin doesn’t match BETTER_AUTH_URL. Set it to exactly what people type in the browser, including the scheme and any non-default port:

You open Inkspace at Set BETTER_AUTH_URL to
http://localhost:6767 http://localhost:6767
http://192.168.1.20:6767 http://192.168.1.20:6767
https://stories.example.com https://stories.example.com

Database service

Use the official postgres:16-alpine image.

Variable Notes
POSTGRES_USER Database user.
POSTGRES_PASSWORD Use a strong, stable password.
POSTGRES_DB Database name, usually inkspace.

Don’t publish the database port to the internet. In the example Compose file only the app is reachable from outside; it talks to db over the internal Compose network.

Persistent data

Mount both of these paths on persistent storage:

Path Container Stores
/var/lib/postgresql/data db Users, stories, comments, likes, ratings, notifications, settings
/inkspace/uploads app Avatars, story covers, story images and comment images

The app runs as the unprivileged node user (UID 1000). A bind-mounted uploads folder must be writable by that user:

sudo chown -R 1000:1000 uploads

Careful with down -v. docker compose down -v deletes Compose-managed volumes, including your database. Only use it when you really want to wipe everything.

Image tags

Images are published to ghcr.io/ak4duy/inkspace:

Tag Built from Use it for
latest master branch Real installs. Recommended.
nightly nightly branch Trying new features early.
X.Y.Z, X.Y Release tags such as v1.2.3 Pinning an exact release.
sha-<commit> Any published commit Reproducing a specific build.

The running version, branch and build date are shown in Settings → Inkspace.

Upload limits

Upload Formats Max size
Avatar JPEG, PNG, WebP 2 MB
Story cover JPEG, PNG, WebP, GIF 10 MB
Story image JPEG, PNG, WebP, GIF 10 MB
Comment image JPEG, PNG, WebP, GIF 10 MB
Data import Inkspace export JSON 25 MB

Files are checked by their actual file signature, not just their extension. Uploads that are never attached to a story or comment are cleaned up automatically after a day.

Security headers

Every response carries X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin and a Permissions-Policy that disables camera, microphone and geolocation. You don’t need to add these at your proxy.