@@ -1,28 +1,28 @@
1 1 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
#!/bin/bash
2 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # fossilrepo entrypoint — starts sshd + gunicorn.
2 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # fossilrepo entrypoint — starts sshd as root, drops to app user for gunicorn.
3 3 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
#
4 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # sshd runs in the background for Fossil SSH access.
5 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # gunicorn runs in the foreground as the main process.
4 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # sshd needs root for port binding and key access.
5 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # gunicorn runs as the unprivileged 'app' user.
6 6 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
7 7 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
set -euo pipefail
8 8 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
9 9 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# Ensure SSH host keys exist (persistent across restarts via volume)
10 10 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then
11 11 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
ssh-keygen -A
12 12 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
fi
13 13 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
14 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Ensure SSH data dir exists and has correct permissions
15 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mkdir -p /data/ssh
14 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Ensure data dirs exist with correct permissions
15 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mkdir -p /data/ssh /data/repos /data/trash
16 16 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
touch /data/ssh/authorized_keys
17 17 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
chmod 600 /data/ssh/authorized_keys
18 18 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
chown -R fossil:fossil /data/ssh
19 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
20 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Ensure fossil user can read repos
21 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- chown -R fossil:fossil /data/repos
19 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ chown -R app:app /data/repos /data/trash
20 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # fossil user needs read access to repos for SSH sync
21 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ chmod -R g+r /data/repos
22 22 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
23 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Start sshd in the background (non-detach mode with -D would block)
23 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Start sshd in the background (runs as root)
24 24 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
/usr/sbin/sshd -p 2222 -e &
25 25 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
SSHD_PID=$!
26 26 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
echo "sshd started (PID $SSHD_PID) on port 2222"
27 27 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
28 28 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# Trap signals to clean up sshd
@@ -31,10 +31,10 @@
31 31 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
kill "$SSHD_PID" 2>/dev/null || true
32 32 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
wait "$SSHD_PID" 2>/dev/null || true
33 33 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
34 34 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
trap cleanup EXIT TERM INT
35 35 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Run gunicorn in the foreground
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- exec gunicorn config.wsgi:application \
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Drop to non-root 'app' user for gunicorn
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ exec gosu app gunicorn config.wsgi:application \
38 38 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
--bind 0.0.0.0:8000 \
39 39 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
--workers 3 \
40 40 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
--timeout 120
41 41 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!