OpenID Connect, off unless four settings are present. It is a second way to the same token the password login mints — every route and the WebSocket still know only a signed JWT — which is why it fits in one file and needs no new dependency: Node imports a JWK itself, so checking an ID token is a signature and five claims. Authorization Code with PKCE, exchanged on the server so the client secret stays there. The browser comes home with a one-time ticket rather than the token, because a token in a redirect URL sits in the history, in the proxy's log and in the referrer of the next request. Somebody the app has not seen gets an account; an account that already exists under that name is linked to the identity rather than duplicated, by subject from then on. Never an administrator. An account made this way has no password here, and the interface stops offering one — but an admin can still set one, which is the way back in if the provider is ever gone. The suite signs in at a provider of its own that signs real RS256 tokens, and holds down the four ways the journey must fail as well as the way it must work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
3.2 KiB
YAML
68 lines
3.2 KiB
YAML
# ─────────────────────────────────────────────
|
|
# InkNote — deploy from the Gitea container registry
|
|
#
|
|
# mkdir -p /srv/inknote/{db,uploads}
|
|
# chown -R 1000:1000 /srv/inknote
|
|
# cp .env.example .env && edit it # secrets + first admin
|
|
# docker login gitea.honeyy.duckdns.org
|
|
# docker compose pull && docker compose up -d
|
|
#
|
|
# Data lives under INKNOTE_DATA_DIR (default /srv/inknote) on the host, so
|
|
# whatever backs up the host also backs up InkNote. Back that path up together
|
|
# with the .env: the notes are encrypted and unreadable without ENCRYPTION_KEY.
|
|
# ─────────────────────────────────────────────
|
|
|
|
services:
|
|
inknote-server:
|
|
image: gitea.honeyy.duckdns.org/docker/inknote-server:latest
|
|
container_name: inknote-server
|
|
restart: unless-stopped
|
|
environment:
|
|
- PORT=4000
|
|
- JWT_SECRET=${JWT_SECRET}
|
|
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
|
|
# Settles who the first administrator is — on an empty database by
|
|
# creating them, on an upgraded one by choosing whom to promote. Ignored
|
|
# entirely once an admin exists, so they can never reset anything.
|
|
- INKNOTE_ADMIN_USER=${INKNOTE_ADMIN_USER:-}
|
|
- INKNOTE_ADMIN_PASSWORD=${INKNOTE_ADMIN_PASSWORD:-}
|
|
- NODE_ENV=production
|
|
# Optional tuning; unset means the server's own defaults apply.
|
|
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-}
|
|
- INKNOTE_MAX_IMAGE_MB=${INKNOTE_MAX_IMAGE_MB:-}
|
|
- INKNOTE_MAX_PDF_MB=${INKNOTE_MAX_PDF_MB:-}
|
|
- MAX_VERSIONS_PER_NOTE=${MAX_VERSIONS_PER_NOTE:-}
|
|
- VERSION_RETENTION_DAYS=${VERSION_RETENTION_DAYS:-}
|
|
- VERSION_COALESCE_MINUTES=${VERSION_COALESCE_MINUTES:-}
|
|
# Signing in through an identity provider — see .env.example. Unset means
|
|
# the app is password-only and the sign-in screen shows nothing about it.
|
|
- INKNOTE_PUBLIC_URL=${INKNOTE_PUBLIC_URL:-}
|
|
- INKNOTE_OIDC_ISSUER=${INKNOTE_OIDC_ISSUER:-}
|
|
- INKNOTE_OIDC_CLIENT_ID=${INKNOTE_OIDC_CLIENT_ID:-}
|
|
- INKNOTE_OIDC_CLIENT_SECRET=${INKNOTE_OIDC_CLIENT_SECRET:-}
|
|
- INKNOTE_OIDC_LABEL=${INKNOTE_OIDC_LABEL:-}
|
|
- INKNOTE_OIDC_SCOPES=${INKNOTE_OIDC_SCOPES:-}
|
|
- INKNOTE_OIDC_REDIRECT_URI=${INKNOTE_OIDC_REDIRECT_URI:-}
|
|
user: "${INKNOTE_UID:-1000}:${INKNOTE_GID:-1000}"
|
|
# Bind mounts, so the data is a plain directory on the host.
|
|
# ${VAR:-fallback} means "VAR, or fallback if VAR is empty" — one or the
|
|
# other, never both. Set INKNOTE_DATA_DIR=/root/inknote and the paths below
|
|
# are /root/inknote/db and /root/inknote/uploads; /srv is then never used.
|
|
volumes:
|
|
- ${INKNOTE_DATA_DIR:-/srv/inknote}/db:/app/data
|
|
- ${INKNOTE_DATA_DIR:-/srv/inknote}/uploads:/app/uploads
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-qO-", "http://localhost:4000/api/health"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
inknote-web:
|
|
image: gitea.honeyy.duckdns.org/docker/inknote-web:latest
|
|
container_name: inknote-web
|
|
restart: unless-stopped
|
|
ports:
|
|
- "3000:80"
|
|
depends_on:
|
|
inknote-server:
|
|
condition: service_healthy |