# Copyright (c) 2026 Brad Root # SPDX-License-Identifier: MPL-2.0 # # Lurker self-hosted — download and run: # curl -O https://raw.githubusercontent.com/amiantos/lurker/main/docker-compose.yml # docker compose up -d # # Then open http://localhost:8015 and create your admin account. # # See docs/SELF_HOSTING.md for the full setup guide, including how to enable # passkeys, web push notifications, and an HTTPS reverse proxy. services: lurker: image: ghcr.io/amiantos/lurker:latest container_name: lurker ports: - '8015:8015' volumes: # All persistent state — SQLite database, session secret, uploads — # lives here. Back this directory up to back up Lurker. - ./data:/app/data environment: - NODE_ENV=production - PORT=8015 - DATABASE_PATH=/app/data/lurker.db # # ───── Optional: Passkeys (WebAuthn) ───────────────────────────────── # Lurker uses username + password by default. To additionally allow # passkey login, set the three vars below to match the public origin # your browsers hit. Passkeys require HTTPS for any non-localhost # hostname — most operators put Lurker behind Caddy or another # reverse proxy first (see docs/SELF_HOSTING.md). # - WEBAUTHN_RP_ID=lurker.example.com # - WEBAUTHN_RP_NAME=Lurker # - WEBAUTHN_ORIGIN=https://lurker.example.com # # ───── Optional: Web Push notifications ────────────────────────────── # Required only if you want push notifications. Must be a valid mailto: # with a real domain (APNs/Safari rejects single-label domains). # - VAPID_SUBJECT=mailto:you@example.com # # ───── Optional: CORS ──────────────────────────────────────────────── # Only needed if you serve the API and the static UI from different # origins (e.g. when developing). For the bundled image, Express # serves both from the same origin and CORS isn't needed. # - CORS_ORIGIN=https://lurker.example.com # # ───── Optional: outbound contact info ─────────────────────────────── # Embedded in our outgoing User-Agent and CTCP VERSION reply so the # operators of services Lurker talks to can reach you if needed. # - USER_AGENT_CONTACT=https://lurker.example.com # # ───── Optional: custom session secret ─────────────────────────────── # By default Lurker generates a 64-byte secret on first boot and # writes it to data/session-secret.key. Set this only if you want # to supply your own (e.g. from a secrets manager). # - SESSION_SECRET=replace-me-with-a-long-random-string # # ───── Optional: built-in IRC bouncer (ZNC-style) ──────────────────── # Attach ordinary IRC clients (WeeChat, irssi, Textual, ...) to your # always-on Lurker connection. Also publish the port above, e.g. # - '6667:6667' # and see docs/SELF_HOSTING.md for login format + TLS options. # - LURKER_BOUNCER_ENABLED=true # - LURKER_BOUNCER_PORT=6667 # # ───── Optional: Link previews & inline media ──────────────────────── # Off by default. A pasted link can unfurl into a card, an image can # render inline, and a video can show a poster frame — but all of the # fetching and media parsing happens in a SECOND container, so this one # never dials a stranger's URL. Run both with: # # curl -O https://raw.githubusercontent.com/amiantos/lurker/main/docker-compose.previews.yml # docker compose -f docker-compose.yml -f docker-compose.previews.yml up -d # # That overlay sets the variable below for you (its presence is the whole # enable switch) and adds the decoder service. See docs/SELF_HOSTING.md # for the egress model and the hardening step. # - LURKER_PREVIEWS_URL=http://lurker-previews:8030 # # ───── Optional: Secure cookie flag ────────────────────────────────── # Off by default so cookies work over plain HTTP (localhost / LAN) and # behind TLS-terminating proxies (Cloudflare Tunnel, Caddy, etc.) # where the container itself sees cleartext. Flip on only if you serve # Lurker over true end-to-end HTTPS. # - COOKIE_SECURE=true restart: unless-stopped