Changeset 09ee2bd in Klonkt


Ignore:
Timestamp:
06/23/2026 09:25:42 PM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
f99bbe8
Parents:
45271b7
Message:

feat: auto-generate SESSION_SECRET if not set (zero-config Docker/manual)

If SESSION_SECRET is missing, generate a strong one on first boot and persist it
to <dataDir>/.session-secret (stable across restarts/updates). Env var still wins.
PUBLIC_BASE_URL already falls back to the request host. So Docker (B) and manual
(C) installs now run with no required .env editing. Docs + .env.example updated;
docker-compose comment translated to English.

Co-Authored-By: Claude <noreply@…>

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • .env.example

    r45271b7 r09ee2bd  
    11NODE_ENV=development
    22PORT=3000
    3 SESSION_SECRET=change-me-to-a-strong-random-string-min-32-chars
     3# Secret used to sign login-session cookies. Leave EMPTY to auto-generate a strong
     4# one on first start (saved to storage/.session-secret, stays stable across
     5# restarts/updates). Or set your own: openssl rand -hex 32
     6SESSION_SECRET=
    47DATABASE_PATH=./storage/database.sqlite
    58MEDIA_PATH=./storage/media
    69
    7 # Canonical public URL of this site (scheme + host, no path/slash). Used for
    8 # links in emails (password reset) instead of request headers — prevents
    9 # host-header spoofing. Not set? Then it falls back to the request host (dev).
    10 PUBLIC_BASE_URL=https://example.com
     10# Canonical public URL of this site (scheme + host, no trailing slash), e.g.
     11# https://yourdomain.com . Used to build correct links in emails (password reset)
     12# and OAuth redirects instead of trusting request headers (anti-spoofing).
     13# Optional: leave empty and it falls back to the request host (fine for local/dev);
     14# set it for production so email/login links point at the right place.
     15PUBLIC_BASE_URL=
    1116
    1217# ── Administrator ───────────────────────────────────────────────────
  • README.md

    r45271b7 r09ee2bd  
    5858git clone https://github.com/roboburr/klonkt.git
    5959cd klonkt
    60 cp .env.example .env          # then edit .env: set SESSION_SECRET + PUBLIC_BASE_URL
     60cp .env.example .env          # works as-is; optionally set PUBLIC_BASE_URL to your domain
    6161docker compose up -d
    6262```
    6363
     64`SESSION_SECRET` is auto-generated on first start, so the defaults work as-is.
    6465Klonkt runs on port 3000 — put your own reverse proxy in front for HTTPS (see
    6566step 5 of Option C). Data (database + media) stays in the `klonkt-data` volume,
     
    7980```
    8081
    81 **2. Create your config** — copy the example and edit it; at minimum set a long
    82 random `SESSION_SECRET` and your `PUBLIC_BASE_URL` (e.g. `https://yourdomain.com`):
     82**2. Create your config.** `SESSION_SECRET` (the key that signs login cookies) is
     83auto-generated on first start, so this works as-is. For production, set
     84`PUBLIC_BASE_URL` to your site address (e.g. `https://yourdomain.com`) so email &
     85login links are correct:
    8386
    8487```bash
    8588cp .env.example .env
    86 nano .env
     89nano .env          # optional: PUBLIC_BASE_URL, plus SMTP / Google if you want them
    8790```
    8891
  • docker-compose.yml

    r45271b7 r09ee2bd  
    1 # Klonkt — zelf-host met Docker Compose.
     1# Klonkt — self-host with Docker Compose.
    22#
    3 #   1. cp .env.example .env   en vul SESSION_SECRET + PUBLIC_BASE_URL in
     3#   1. cp .env.example .env     (works as-is: SESSION_SECRET is auto-generated;
     4#                                optionally set PUBLIC_BASE_URL to your domain so
     5#                                email/login links are correct)
    46#   2. docker compose up -d
    5 #   3. open je site en maak via /auth/register je beheerdersaccount aan
     7#   3. open your site and create your admin account at /auth/register
    68#
    7 # Standaard luistert de app op poort 3000. Zet er een reverse-proxy (Caddy/
    8 # nginx) vóór voor HTTPS op je domein — zie README.
     9# The app listens on port 3000. Put a reverse proxy (Caddy/nginx) in front for
     10# HTTPS on your domain — see README.
    911services:
    1012  klonkt:
  • src/server.js

    r45271b7 r09ee2bd  
    1313import path from 'path';
    1414import fs from 'fs';
     15import crypto from 'crypto';
    1516import { fileURLToPath } from 'url';
    1617import http from 'http';
     
    6364import changelogRoutes from './routes/changelog.js';
    6465
     66// SESSION_SECRET: use the env var if set. Otherwise auto-generate a strong one
     67// and persist it next to the database, so it stays stable across restarts and
     68// updates. This lets Docker / bare-Node installs run with zero manual config.
    6569if (!process.env.SESSION_SECRET) {
    66   console.error('❌ FATAL: SESSION_SECRET is required');
    67   process.exit(1);
     70  const dataDir = path.dirname(process.env.DATABASE_PATH || './storage/database.sqlite');
     71  const secretFile = path.join(dataDir, '.session-secret');
     72  try { process.env.SESSION_SECRET = fs.readFileSync(secretFile, 'utf8').trim(); } catch { /* not yet generated */ }
     73  if (!process.env.SESSION_SECRET) {
     74    fs.mkdirSync(dataDir, { recursive: true });
     75    process.env.SESSION_SECRET = crypto.randomBytes(32).toString('hex');
     76    fs.writeFileSync(secretFile, process.env.SESSION_SECRET, { mode: 0o600 });
     77    console.log(`🔑 Generated a SESSION_SECRET (stored in ${secretFile})`);
     78  }
    6879}
    6980
     81// A SESSION_SECRET that was explicitly set in the env must still be strong in prod.
    7082if (process.env.NODE_ENV === 'production' && process.env.SESSION_SECRET.length < 32) {
    71   console.error('❌ FATAL: SESSION_SECRET too weak for production');
     83  console.error('❌ FATAL: SESSION_SECRET is too weak for production (set a longer, random one in .env)');
    7284  process.exit(1);
    7385}
Note: See TracChangeset for help on using the changeset viewer.