Shorten .env.example; move the long explanations to the readme

76 lines of commentary for five settings was more wall than help. The
file now says what to set; the reasoning behind the data directory, and
the two ways of putting it under /root, live in the readme where there is
room for them.

Also brought the deployment section up to date: it still told people to
export secrets by hand and run docker-compose, with no word about the
first admin, which is now the step that decides whether you can log in at
all.

INKNOTE_DATA_DIR stays commented out — one .env serves both compose
files, so setting it would drag local development off ./data too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-08 13:17:30 +02:00
1 parent 4e93259c04
commit 6dcb77fa73
2 files changed
+71 -75

No files matched your search

+21 -66
View File
@@ -1,76 +1,31 @@
# cp .env.example .env — and fill it in. Docker Compose reads .env from this
# directory, next to docker-compose.yml; nothing looks for it anywhere else.
#
# Back the finished .env up together with the database: without ENCRYPTION_KEY
# the stored notes cannot be read again, and a backup of one without the other
# is worth nothing.
# cp .env.example .env — Compose reads it from this directory.
# Back the finished .env up with the database: without ENCRYPTION_KEY the
# stored notes cannot be read again.
# Signs session tokens. Changing it logs everyone out.
# openssl rand -hex 32
# Both: openssl rand -hex 32
JWT_SECRET=
# Encrypts note bodies at rest. LOSING THIS MEANS LOSING THE NOTES.
# Must be exactly 32 bytes as hex.
# openssl rand -hex 32
ENCRYPTION_KEY=
# The first administrator.
#
# There is no public sign-up — accounts are created by an admin inside the app
# under Account → Administration. These two settle who the first one is:
#
# empty database → the account is created from both values
# existing users, → INKNOTE_ADMIN_USER names which of them becomes admin.
# no admin yet Without it, the oldest account is promoted.
# an admin exists → both are ignored entirely
#
# So they can never reset an existing password or take rights away; the worst
# they can do on a running instance is nothing.
# The first administrator. There is no public sign-up — every other account is
# created in the app under Account → Administration. Used only until an admin
# exists, then ignored, so they can never reset anything later.
INKNOTE_ADMIN_USER=
INKNOTE_ADMIN_PASSWORD=
# ── Where the data lives ──
# A plain directory on the Docker host — a bind mount, not a Docker volume, so
# that whatever backs up the host also backs up InkNote. Create it first; the
# container runs unprivileged and cannot create it for you:
#
# Where the notes are kept on the host. Defaults to /srv/inknote in production
# and ./data for development — leave it commented unless you want another path,
# since one .env serves both. Create the directory first, or Docker creates it
# as root and the server (uid 1000) cannot write:
# mkdir -p /srv/inknote/{db,uploads} && chown -R 1000:1000 /srv/inknote
# INKNOTE_DATA_DIR=/srv/inknote
#
# INKNOTE_DATA_DIR=/srv/inknote # dev compose defaults to ./data
# INKNOTE_UID=1000 # must own the directory above
# INKNOTE_GID=1000
#
# The path must start with / or ./ — anything else Docker reads as the name of
# a named volume, and a name containing a slash simply fails.
#
# ── Putting it under /root ──
# /root is normally mode 0700, and uid 1000 cannot even pass through it, so the
# server would fail to write however the directory itself is owned. Two ways
# out; the first keeps the unprivileged container and is the better trade:
#
# A) let uid 1000 traverse /root, without making it readable:
# mkdir -p /root/inknote/{db,uploads}
# chown -R 1000:1000 /root/inknote
# chmod o+x /root # traverse only — ls /root still refused
# INKNOTE_DATA_DIR=/root/inknote
#
# B) run the container as root instead — no chown, no chmod, but a break-out
# lands on root rather than on an unprivileged user:
# INKNOTE_DATA_DIR=/root/inknote
# INKNOTE_UID=0
# INKNOTE_GID=0
#
# Neither is needed under /srv or /opt, which is why those are the default.
# Under /root also run "chmod o+x /root", or the server cannot reach it at all.
# That and the alternative: readme.md → Where the data lives.
# ── Optional tuning ──
# Leave unset to keep the defaults shown.
# MAX_VERSIONS_PER_NOTE=50 # versions kept per note
# VERSION_RETENTION_DAYS=90 # and for how long
# VERSION_COALESCE_MINUTES=5 # edits within this window share a version
#
# Only if the UI is served from a different host than the API. With a reverse
# proxy in front, or the bundled nginx, leave it empty — same-origin needs none.
# ALLOWED_ORIGINS=https://notes.example.com
#
# PORT is deliberately not here: the bundled nginx proxies to port 4000 by
# name, so changing it would only break that.
# ── Optional ── unset keeps the default shown
# INKNOTE_UID=1000 # must own INKNOTE_DATA_DIR
# INKNOTE_GID=1000
# MAX_VERSIONS_PER_NOTE=50
# VERSION_RETENTION_DAYS=90
# VERSION_COALESCE_MINUTES=5
# ALLOWED_ORIGINS= # only if the UI is on another host