/root is mode 0700 and the container runs as uid 1000, so it cannot even traverse it — the server fails to write no matter who owns the directory underneath. Both ways out are written down, with the trade each makes: chmod o+x /root keeps the unprivileged container and still refuses ls, running as uid 0 avoids the chmod but puts a break-out on root. Also noted that the path has to start with / or ./, since anything else is read as a named volume name. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
77 lines
3.2 KiB
Bash
77 lines
3.2 KiB
Bash
# 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.
|
|
|
|
# Signs session tokens. Changing it logs everyone out.
|
|
# 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.
|
|
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:
|
|
#
|
|
# mkdir -p /srv/inknote/{db,uploads} && chown -R 1000:1000 /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.
|
|
|
|
# ── 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.
|