Skip to content

Commit aa5846b

Browse files
committed
fix(docker): resolve /app/data permission denied on volume mounts
Docker named volumes and host bind-mounts may be owned by root, causing "open data/model_pricing.sha256: permission denied" when the container runs as the non-root sub2api user. Add an entrypoint script that fixes /app/data ownership before dropping to sub2api via su-exec. Replace USER directive with the entrypoint approach across all three Dockerfiles and update both GoReleaser configs to include the script in Docker build contexts.
1 parent 594a0ad commit aa5846b

6 files changed

Lines changed: 53 additions & 10 deletions

File tree

.goreleaser.simple.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ dockers:
4747
- "ghcr.io/{{ .Env.GITHUB_REPO_OWNER_LOWER }}/sub2api:latest"
4848
dockerfile: Dockerfile.goreleaser
4949
use: buildx
50+
extra_files:
51+
- deploy/docker-entrypoint.sh
5052
build_flag_templates:
5153
- "--platform=linux/amd64"
5254
- "--label=org.opencontainers.image.version={{ .Version }}"

.goreleaser.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ dockers:
6363
- "{{ .Env.DOCKERHUB_USERNAME }}/sub2api:{{ .Version }}-amd64"
6464
dockerfile: Dockerfile.goreleaser
6565
use: buildx
66+
extra_files:
67+
- deploy/docker-entrypoint.sh
6668
build_flag_templates:
6769
- "--platform=linux/amd64"
6870
- "--label=org.opencontainers.image.version={{ .Version }}"
@@ -76,6 +78,8 @@ dockers:
7678
- "{{ .Env.DOCKERHUB_USERNAME }}/sub2api:{{ .Version }}-arm64"
7779
dockerfile: Dockerfile.goreleaser
7880
use: buildx
81+
extra_files:
82+
- deploy/docker-entrypoint.sh
7983
build_flag_templates:
8084
- "--platform=linux/arm64"
8185
- "--label=org.opencontainers.image.version={{ .Version }}"
@@ -89,6 +93,8 @@ dockers:
8993
- "ghcr.io/{{ .Env.GITHUB_REPO_OWNER_LOWER }}/sub2api:{{ .Version }}-amd64"
9094
dockerfile: Dockerfile.goreleaser
9195
use: buildx
96+
extra_files:
97+
- deploy/docker-entrypoint.sh
9298
build_flag_templates:
9399
- "--platform=linux/amd64"
94100
- "--label=org.opencontainers.image.version={{ .Version }}"
@@ -102,6 +108,8 @@ dockers:
102108
- "ghcr.io/{{ .Env.GITHUB_REPO_OWNER_LOWER }}/sub2api:{{ .Version }}-arm64"
103109
dockerfile: Dockerfile.goreleaser
104110
use: buildx
111+
extra_files:
112+
- deploy/docker-entrypoint.sh
105113
build_flag_templates:
106114
- "--platform=linux/arm64"
107115
- "--label=org.opencontainers.image.version={{ .Version }}"

Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ LABEL org.opencontainers.image.source="https://github.com/Wei-Shaw/sub2api"
9292
RUN apk add --no-cache \
9393
ca-certificates \
9494
tzdata \
95+
su-exec \
9596
libpq \
9697
zstd-libs \
9798
lz4-libs \
@@ -120,8 +121,9 @@ COPY --from=backend-builder --chown=sub2api:sub2api /app/backend/resources /app/
120121
# Create data directory
121122
RUN mkdir -p /app/data && chown sub2api:sub2api /app/data
122123

123-
# Switch to non-root user
124-
USER sub2api
124+
# Copy entrypoint script (fixes volume permissions then drops to sub2api)
125+
COPY deploy/docker-entrypoint.sh /app/docker-entrypoint.sh
126+
RUN chmod +x /app/docker-entrypoint.sh
125127

126128
# Expose port (can be overridden by SERVER_PORT env var)
127129
EXPOSE 8080
@@ -130,5 +132,6 @@ EXPOSE 8080
130132
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
131133
CMD wget -q -T 5 -O /dev/null http://localhost:${SERVER_PORT:-8080}/health || exit 1
132134

133-
# Run the application
134-
ENTRYPOINT ["/app/sub2api"]
135+
# Run the application (entrypoint fixes /app/data ownership then execs as sub2api)
136+
ENTRYPOINT ["/app/docker-entrypoint.sh"]
137+
CMD ["/app/sub2api"]

Dockerfile.goreleaser

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ RUN apk add --no-cache \
2121
ca-certificates \
2222
tzdata \
2323
curl \
24+
su-exec \
2425
libpq \
2526
zstd-libs \
2627
lz4-libs \
@@ -47,11 +48,15 @@ COPY sub2api /app/sub2api
4748
# Create data directory
4849
RUN mkdir -p /app/data && chown -R sub2api:sub2api /app
4950

50-
USER sub2api
51+
# Copy entrypoint script (fixes volume permissions then drops to sub2api)
52+
COPY deploy/docker-entrypoint.sh /app/docker-entrypoint.sh
53+
RUN chmod +x /app/docker-entrypoint.sh
5154

5255
EXPOSE 8080
5356

5457
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
5558
CMD curl -f http://localhost:${SERVER_PORT:-8080}/health || exit 1
5659

57-
ENTRYPOINT ["/app/sub2api"]
60+
# Run the application (entrypoint fixes /app/data ownership then execs as sub2api)
61+
ENTRYPOINT ["/app/docker-entrypoint.sh"]
62+
CMD ["/app/sub2api"]

deploy/Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ RUN apk add --no-cache \
8282
ca-certificates \
8383
tzdata \
8484
curl \
85+
su-exec \
8586
&& rm -rf /var/cache/apk/*
8687

8788
# Create non-root user
@@ -97,8 +98,9 @@ COPY --from=backend-builder /app/sub2api /app/sub2api
9798
# Create data directory
9899
RUN mkdir -p /app/data && chown -R sub2api:sub2api /app
99100

100-
# Switch to non-root user
101-
USER sub2api
101+
# Copy entrypoint script (fixes volume permissions then drops to sub2api)
102+
COPY deploy/docker-entrypoint.sh /app/docker-entrypoint.sh
103+
RUN chmod +x /app/docker-entrypoint.sh
102104

103105
# Expose port (can be overridden by SERVER_PORT env var)
104106
EXPOSE 8080
@@ -107,5 +109,6 @@ EXPOSE 8080
107109
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
108110
CMD wget -q -T 5 -O /dev/null http://localhost:${SERVER_PORT:-8080}/health || exit 1
109111

110-
# Run the application
111-
ENTRYPOINT ["/app/sub2api"]
112+
# Run the application (entrypoint fixes /app/data ownership then execs as sub2api)
113+
ENTRYPOINT ["/app/docker-entrypoint.sh"]
114+
CMD ["/app/sub2api"]

deploy/docker-entrypoint.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/sh
2+
set -e
3+
4+
# Fix data directory permissions when running as root.
5+
# Docker named volumes / host bind-mounts may be owned by root,
6+
# preventing the non-root sub2api user from writing files.
7+
if [ "$(id -u)" = "0" ]; then
8+
mkdir -p /app/data
9+
chown -R sub2api:sub2api /app/data
10+
# Re-invoke this script as sub2api so the flag-detection below
11+
# also runs under the correct user.
12+
exec su-exec sub2api "$0" "$@"
13+
fi
14+
15+
# Compatibility: if the first arg looks like a flag (e.g. --help),
16+
# prepend the default binary so it behaves the same as the old
17+
# ENTRYPOINT ["/app/sub2api"] style.
18+
if [ "${1#-}" != "$1" ]; then
19+
set -- /app/sub2api "$@"
20+
fi
21+
22+
exec "$@"

0 commit comments

Comments
 (0)