Docker
Every config option can be set as an environment variable, see Configuration.
First create a .env file next to the compose file with a random secret and the password of the first admin. Anyone
who knows the secret can sign in as any user, so never reuse a value from an example:
printf 'LINKSHELF_JWT_SECRET=%s\nLINKSHELF_ADMIN_PASSWORD=%s\n' "$(openssl rand -base64 48)" "$(openssl rand -base64 18)" > .env
services:
linkshelf:
image: ghcr.io/m-mattia-m/linkshelf:latest # pin a version instead of latest
restart: unless-stopped
ports:
- "3000:3000" # frontend
- "8085:8085" # backend
environment:
DATABASE_ENGINE: POSTGRES
DATABASE_HOST: postgres
DATABASE_PORT: 5432
DATABASE_PASSWORD: linkshelf # change
# Required, at least 32 bytes. Comes from .env, see above.
AUTHENTICATION_JWTSECRET: ${LINKSHELF_JWT_SECRET:?set LINKSHELF_JWT_SECRET in .env}
# The first admin, created on the first start only. Use your own address.
AUTHENTICATION_BOOTSTRAPADMIN_EMAIL: you@example.com # change
AUTHENTICATION_BOOTSTRAPADMIN_PASSWORD: ${LINKSHELF_ADMIN_PASSWORD:?set LINKSHELF_ADMIN_PASSWORD in .env}
# No SMTP? Then turn these off, or new users can't sign in.
# AUTHENTICATION_EMAILVERIFICATION_ENABLED: false
# AUTHENTICATION_PASSWORDRESET_ENABLED: false
depends_on:
# The backend exits if its first DB ping fails, so wait for postgres.
postgres:
condition: service_healthy
postgres:
image: postgres
restart: unless-stopped
shm_size: 128mb
environment:
POSTGRES_USER: linkshelf
POSTGRES_PASSWORD: linkshelf # change, same as above
POSTGRES_DB: linkshelf
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U linkshelf -d linkshelf" ]
interval: 2s
timeout: 3s
retries: 30
volumes:
postgres-data:
docker compose up -d
Open http://localhost:3000 and sign in with the bootstrap admin: the email above and the password from .env
(grep LINKSHELF_ADMIN_PASSWORD .env).
The admin account is only created when it doesn't exist yet. Later starts never touch it, so a password you change after
signing in stays changed. Once you are in, you can remove the two AUTHENTICATION_BOOTSTRAPADMIN_* lines.
Behind a domain
The browser talks to the backend directly, so it needs a public address of its own:
NUXT_PUBLIC_API_BASE: public URL of the backend, e.g.https://api.example.comAPP_FRONTENDURL: public URL of the frontend, used in emailsSERVER_HOST: public host of the backend
Add APP_STRICTORIGINS=true to lock the API to those addresses, see
Strict origins. To also reach the instance on another domain, add it
to APP_ADDITIONALORIGINS (comma-separated for more than one), see Reachable on more than one
domain.
Website and SEO
Optional. NUXT_PUBLIC_SITE_URL is the public URL of your own instance, e.g. https://links.example.org. Set it to
enable a sitemap at /sitemap.xml, a robots.txt that points to it, canonical and Open Graph URLs, and server-side
rendering of the landing page, /about, /cloud and the docs. Requests to any other host, such as a shelf on a custom
domain, are not affected. Leave it empty if the instance is only used for shelves.
Analytics
Optional, cookie-free visitor analytics via Plausible, off by default.
NUXT_PUBLIC_PLAUSIBLE_ENABLED:trueto turn it onNUXT_PUBLIC_PLAUSIBLE_DOMAIN: the site identifier registered in Plausible. Falls back to the request's hostname, so set it when the instance is reachable on more than one domainNUXT_PUBLIC_PLAUSIBLE_API_HOST: your Plausible instance, e.g.https://plausible.example.com. Defaults tohttps://plausible.ioNUXT_PUBLIC_PLAUSIBLE_PROXY:trueto route the script and API calls through this app's own domain (under/_plausible), to reduce ad-blocker interference
environment:
NUXT_PUBLIC_PLAUSIBLE_ENABLED: "true"
NUXT_PUBLIC_PLAUSIBLE_DOMAIN: links.example.org
NUXT_PUBLIC_PLAUSIBLE_API_HOST: https://plausible.example.org
Config file
To use a file instead of environment variables, mount it and point to it:
environment:
CONFIGURATION_FILE_PATH: /app/config.local.yaml
volumes:
- ./config.local.yaml:/app/config.local.yaml
It overrides the defaults from config.default.yaml, environment variables win over both.
Themes and images
Mount a directory for your own instance themes and images.
Custom domains for shelves
See Custom domains. Short version: put a reverse proxy in front of port 3000 that
passes the original Host header (or X-Forwarded-Host) on.