Skip to content

Commit 6ebf9bb

Browse files
committed
docker!: switch to puid/guid runtime user mapping
1 parent 0a10003 commit 6ebf9bb

6 files changed

Lines changed: 78 additions & 47 deletions

File tree

.env.sample

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ SSH_SERVER_PORT=2222
88
FQDN=your.domain.com
99
NEXTAUTH_URL=https://your.domain.com
1010

11-
# Secrects
11+
# Secrets
1212
NEXTAUTH_SECRET=your-secret
1313
CRONJOB_KEY=your-other-secret
1414

15-
# UID:GID must match the user and group ID of the host folders and must be > 1000
16-
# If you want to use a different user than 1001:1001, you must rebuild the image yourself.
17-
UID=1001
18-
GID=1001
15+
# PUID/PGID: UID and GID the app will run as inside the container.
16+
# Must match the owner of your volume directories on the host.
17+
# Must be > 0 (root is not allowed).
18+
PUID=1000
19+
PGID=1000
1920

2021
# Config and data folders (volume mounts)
21-
# The host folders must be owned by the user with UID and GID specified above
22+
# The host folders must be owned by the user with PUID and PGID specified above
2223
CONFIG_PATH=./config
2324
SSH_PATH=./ssh
2425
SSH_HOST=./ssh_host

Dockerfile

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
ARG UID=1001
2-
ARG GID=1001
3-
41
FROM node:22-bookworm-slim as base
52

63
# build stage
@@ -33,18 +30,18 @@ RUN pnpm run build
3330
# run stage
3431
FROM base AS runner
3532

36-
ARG UID
37-
ARG GID
38-
3933
ENV NODE_ENV production
4034
ENV HOSTNAME=
4135

4236
RUN echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list
4337
RUN apt-get update && apt-get install -y \
44-
supervisor curl jq jc borgbackup/bookworm-backports openssh-server && \
38+
supervisor curl jq jc borgbackup/bookworm-backports openssh-server gosu && \
4539
apt-get clean && rm -rf /var/lib/apt/lists/*
4640

47-
RUN groupadd -g ${GID} borgwarehouse && useradd -m -u ${UID} -g ${GID} borgwarehouse
41+
# Remove the default 'node' user (UID 1000) to avoid conflicts with PUID=1000
42+
RUN userdel -r node 2>/dev/null || true
43+
44+
RUN groupadd -g 1001 borgwarehouse && useradd -m -u 1001 -g 1001 borgwarehouse
4845

4946
RUN cp /etc/ssh/moduli /home/borgwarehouse/
5047

@@ -58,7 +55,8 @@ COPY --from=builder --chown=borgwarehouse:borgwarehouse /app/.next/static ./.nex
5855
COPY --from=builder --chown=borgwarehouse:borgwarehouse /app/docker/supervisord.conf ./
5956
COPY --from=builder --chown=borgwarehouse:borgwarehouse /app/docker/sshd_config ./
6057

61-
USER borgwarehouse
58+
# Container starts as root to handle PUID/PGID remapping at runtime.
59+
# The entrypoint drops to borgwarehouse before starting the app.
6260

6361
EXPOSE 3000 22
6462

docker-compose.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@ services:
55
#build:
66
# context: .
77
# dockerfile: Dockerfile
8-
# args:
9-
# - UID=${UID}
10-
# - GID=${GID}
118
image: borgwarehouse/borgwarehouse
12-
user: '${UID:?UID variable missing}:${GID:?GID variable missing}'
139
ports:
1410
- '${WEB_SERVER_PORT:?WEB_SERVER_PORT variable missing}:3000'
1511
- '${SSH_SERVER_PORT:?SSH_SERVER_PORT variable missing}:22'
@@ -20,7 +16,7 @@ services:
2016
- ${SSH_PATH:?SSH_PATH variable missing}:/home/borgwarehouse/.ssh
2117
- ${SSH_HOST:?SSH_HOST variable missing}:/etc/ssh
2218
- ${BORG_REPOSITORY_PATH:?BORG_REPOSITORY_PATH variable missing}:/home/borgwarehouse/repos
23-
# Apprise is used to send notifications, it's optional. http://apprise:8000 is the URL to use in BorgWarehouse.
19+
# Apprise is used to send notifications, it's optional. http://apprise:8000 is the URL to use in BorgWarehouse.
2420
apprise:
2521
container_name: apprise
2622
image: caronc/apprise

docker/docker-bw-init.sh

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,55 @@
22

33
set -e
44

5+
PUID=${PUID:-1000}
6+
PGID=${PGID:-1000}
7+
58
SSH_DIR="/home/borgwarehouse/.ssh"
69
AUTHORIZED_KEYS_FILE="$SSH_DIR/authorized_keys"
710
REPOS_DIR="/home/borgwarehouse/repos"
11+
CONFIG_DIR="/home/borgwarehouse/app/config"
12+
13+
print_green() { echo -e "\e[92m$1\e[0m"; }
14+
print_red() { echo -e "\e[91m$1\e[0m"; }
15+
16+
# 1. Remap borgwarehouse to PUID:PGID
17+
18+
remap_user() {
19+
if [ "$PUID" -eq 0 ] || [ "$PGID" -eq 0 ]; then
20+
print_red "[ERROR] PUID and PGID cannot be 0. Running the app as root is not allowed."
21+
exit 1
22+
fi
823

9-
print_green() {
10-
echo -e "\e[92m$1\e[0m";
24+
print_green "Mapping borgwarehouse to UID=$PUID GID=$PGID"
25+
groupmod -o -g "$PGID" borgwarehouse
26+
usermod -o -u "$PUID" -p '*' borgwarehouse
27+
28+
# Chown the application directory only (never the user's volume mounts)
29+
chown -R borgwarehouse:borgwarehouse /home/borgwarehouse/app
30+
chown borgwarehouse:borgwarehouse /home/borgwarehouse /home/borgwarehouse/moduli
1131
}
12-
print_red() {
13-
echo -e "\e[91m$1\e[0m";
32+
33+
# 2. Check volume is mounted and writable
34+
35+
check_volume() {
36+
local dir=$1
37+
local name=$2
38+
39+
if [ ! -d "$dir" ]; then
40+
print_red "[ERROR] Volume '$name' is not mounted. Expected path: $dir"
41+
print_red " Check the volumes section in your docker-compose.yml."
42+
exit 1
43+
fi
44+
45+
if ! gosu borgwarehouse test -w "$dir" 2>/dev/null; then
46+
print_red "[ERROR] Volume '$name' ($dir) is not writable by UID=$PUID GID=$PGID."
47+
print_red " Fix on the host: chown -R $PUID:$PGID <your-host-path-for-$name>"
48+
exit 1
49+
fi
1450
}
1551

52+
# 3. Generate SSH host keys if needed
53+
1654
init_ssh_server() {
1755
if [ -z "$(ls -A /etc/ssh)" ]; then
1856
print_green "/etc/ssh is empty, generating SSH host keys..."
@@ -25,31 +63,19 @@ init_ssh_server() {
2563
fi
2664
}
2765

28-
check_ssh_directory() {
29-
if [ ! -d "$SSH_DIR" ]; then
30-
print_red "The .ssh directory does not exist, you need to mount it as docker volume."
31-
exit 1
32-
else
33-
chmod 700 "$SSH_DIR"
34-
fi
35-
}
66+
# 4. Setup authorized_keys
3667

37-
create_authorized_keys_file() {
68+
setup_authorized_keys() {
3869
if [ ! -f "$AUTHORIZED_KEYS_FILE" ]; then
39-
print_green "The authorized_keys file does not exist, creating..."
70+
print_green "Creating authorized_keys file..."
4071
touch "$AUTHORIZED_KEYS_FILE"
4172
fi
42-
chmod 600 "$AUTHORIZED_KEYS_FILE"
73+
chown borgwarehouse:borgwarehouse "$SSH_DIR" "$AUTHORIZED_KEYS_FILE"
74+
chmod 700 "$SSH_DIR"
75+
chmod 600 "$AUTHORIZED_KEYS_FILE"
4376
}
4477

45-
check_repos_directory() {
46-
if [ ! -d "$REPOS_DIR" ]; then
47-
print_red "The repos directory does not exist, you need to mount it as docker volume."
48-
exit 2
49-
else
50-
chmod 700 "$REPOS_DIR"
51-
fi
52-
}
78+
# 5. Read SSH fingerprints
5379

5480
get_SSH_fingerprints() {
5581
print_green "Getting SSH fingerprints..."
@@ -61,6 +87,8 @@ get_SSH_fingerprints() {
6187
export SSH_SERVER_FINGERPRINT_ECDSA="$ECDSA_FINGERPRINT"
6288
}
6389

90+
# 6. Check secrets
91+
6492
check_env() {
6593
if [ -z "$CRONJOB_KEY" ]; then
6694
CRONJOB_KEY=$(openssl rand -base64 32)
@@ -75,11 +103,16 @@ check_env() {
75103
fi
76104
}
77105

106+
# Run
107+
108+
remap_user
78109
check_env
110+
mkdir -p /run/sshd
79111
init_ssh_server
80-
check_ssh_directory
81-
create_authorized_keys_file
82-
check_repos_directory
112+
check_volume "$SSH_DIR" ".ssh"
113+
check_volume "$REPOS_DIR" "repos"
114+
check_volume "$CONFIG_DIR" "config"
115+
setup_authorized_keys
83116
get_SSH_fingerprints
84117

85118
print_green "Successful initialization. BorgWarehouse is ready !"

docker/sshd_config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Port 22
2-
PidFile /home/borgwarehouse/tmp/sshd.pid
2+
PidFile /run/sshd.pid
33
AllowUsers borgwarehouse
44
LogLevel INFO
55
SyslogFacility AUTH

docker/supervisord.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[supervisord]
22
nodaemon=true
3+
user=root
4+
pidfile=/tmp/supervisord.pid
35
logfile=/dev/stdout
46
logfile_maxbytes=0
57
loglevel=error
@@ -14,6 +16,7 @@ redirect_stderr=false
1416

1517
[program:borgwarehouse]
1618
command=/usr/local/bin/node server.js
19+
user=borgwarehouse
1720
stdout_logfile=/dev/stdout
1821
stdout_logfile_maxbytes=0
1922
stderr_logfile=/dev/stderr

0 commit comments

Comments
 (0)