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.com
  • APP_FRONTENDURL: public URL of the frontend, used in emails
  • SERVER_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: true to turn it on
  • NUXT_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 domain
  • NUXT_PUBLIC_PLAUSIBLE_API_HOST: your Plausible instance, e.g. https://plausible.example.com. Defaults to https://plausible.io
  • NUXT_PUBLIC_PLAUSIBLE_PROXY: true to 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.

Made with by all contributors