This repository was archived by the owner on Feb 27, 2026. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 97
Expand file tree
/
Copy pathDockerfile
More file actions
263 lines (202 loc) · 8.36 KB
/
Dockerfile
File metadata and controls
263 lines (202 loc) · 8.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
FROM node:24-alpine AS base
# Install system dependencies
RUN apk add --no-cache \
gcompat \
supervisor \
curl \
wget \
openssl \
su-exec
# Enable pnpm
RUN corepack enable pnpm
# Install storage system for S3-compatible storage
COPY infra/install-minio.sh /tmp/install-minio.sh
RUN chmod +x /tmp/install-minio.sh && /tmp/install-minio.sh
# Install storage client (mc) for appropriate architecture
COPY infra/install-mc.sh /tmp/install-mc.sh
RUN chmod +x /tmp/install-mc.sh && /tmp/install-mc.sh
# Set working directory
WORKDIR /app
# === SERVER BUILD STAGE ===
FROM base AS server-deps
WORKDIR /app/server
# Copy server package files
COPY apps/server/package*.json ./
COPY apps/server/pnpm-lock.yaml ./
# Install server dependencies
RUN pnpm install --frozen-lockfile
FROM base AS server-builder
WORKDIR /app/server
# Copy server dependencies
COPY --from=server-deps /app/server/node_modules ./node_modules
# Copy server source code
COPY apps/server/ ./
# Generate Prisma client
RUN npx prisma generate
# Build server
RUN pnpm build
# === WEB BUILD STAGE ===
FROM base AS web-deps
WORKDIR /app/web
# Copy web package files
COPY apps/web/package.json apps/web/pnpm-lock.yaml ./
# Install web dependencies
RUN pnpm install --frozen-lockfile
FROM base AS web-builder
WORKDIR /app/web
# Copy web dependencies
COPY --from=web-deps /app/web/node_modules ./node_modules
# Copy web source code
COPY apps/web/ ./
# Set environment variables for build
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
# Build web application
RUN pnpm run build
# === PRODUCTION STAGE ===
FROM base AS runner
# Set production environment
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV API_BASE_URL=http://127.0.0.1:3333
# Define build arguments for user/group configuration (defaults to current values)
ARG PALMR_UID=1001
ARG PALMR_GID=1001
# Create application user with configurable UID/GID
RUN addgroup --system --gid ${PALMR_GID} nodejs
RUN adduser --system --uid ${PALMR_UID} --ingroup nodejs palmr
# Create application directories
RUN mkdir -p /app/palmr-app /app/web /app/infra /home/palmr/.npm /home/palmr/.cache
RUN chown -R palmr:nodejs /app /home/palmr
# === Copy Server Files to /app/palmr-app (separate from /app/server for bind mounts) ===
WORKDIR /app/palmr-app
# Copy server production files
COPY --from=server-builder --chown=palmr:nodejs /app/server/dist ./dist
COPY --from=server-builder --chown=palmr:nodejs /app/server/node_modules ./node_modules
COPY --from=server-builder --chown=palmr:nodejs /app/server/prisma ./prisma
COPY --from=server-builder --chown=palmr:nodejs /app/server/package.json ./
# Copy password reset script and make it executable
COPY --from=server-builder --chown=palmr:nodejs /app/server/reset-password.sh ./
COPY --from=server-builder --chown=palmr:nodejs /app/server/src/scripts/ ./src/scripts/
RUN chmod +x ./reset-password.sh
# Copy seed file to the shared location for bind mounts
RUN mkdir -p /app/server/prisma
COPY --from=server-builder --chown=palmr:nodejs /app/server/prisma/seed.js /app/server/prisma/seed.js
# === Copy Web Files ===
WORKDIR /app/web
# Copy web production files
COPY --from=web-builder --chown=palmr:nodejs /app/web/public ./public
COPY --from=web-builder --chown=palmr:nodejs /app/web/.next/standalone ./
COPY --from=web-builder --chown=palmr:nodejs /app/web/.next/static ./.next/static
# === Setup Supervisor ===
WORKDIR /app
# Create supervisor configuration
RUN mkdir -p /etc/supervisor/conf.d
# Copy server start script and configuration files
COPY infra/server-start.sh /app/server-start.sh
COPY infra/start-minio.sh /app/start-minio.sh
COPY infra/minio-setup.sh /app/minio-setup.sh
COPY infra/load-minio-credentials.sh /app/load-minio-credentials.sh
COPY infra/configs.json /app/infra/configs.json
COPY infra/providers.json /app/infra/providers.json
COPY infra/check-missing.js /app/infra/check-missing.js
RUN chmod +x /app/server-start.sh /app/start-minio.sh /app/minio-setup.sh /app/load-minio-credentials.sh
RUN chown -R palmr:nodejs /app/server-start.sh /app/start-minio.sh /app/minio-setup.sh /app/load-minio-credentials.sh /app/infra
# Copy supervisor configuration
COPY infra/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Create main startup script
COPY <<EOF /app/start.sh
#!/bin/sh
set -e
echo "Starting Palmr Application..."
echo "Storage Mode: \${ENABLE_S3:-false}"
echo "Secure Site: \${SECURE_SITE:-false}"
echo "Encryption: \${DISABLE_FILESYSTEM_ENCRYPTION:-true}"
echo "Database: SQLite"
# Set global environment variables
export DATABASE_URL="file:/app/server/prisma/palmr.db"
export NEXT_PUBLIC_DEFAULT_LANGUAGE=\${DEFAULT_LANGUAGE:-en-US}
# Ensure /app/server directory exists for bind mounts
mkdir -p /app/server/uploads /app/server/temp-uploads /app/server/prisma /app/server/minio-data
# CRITICAL: Fix permissions BEFORE starting any services
# This runs on EVERY startup to handle updates and corrupted metadata
echo "🔐 Fixing permissions for internal storage..."
# USE ENVIRONMENT VARIABLES: Allow runtime UID/GID configuration
# Falls back to palmr user's UID/GID if not specified
TARGET_UID=\${PALMR_UID:-\$(id -u palmr 2>/dev/null || echo "1001")}
TARGET_GID=\${PALMR_GID:-\$(id -g palmr 2>/dev/null || echo "1001")}
echo " Target user: palmr (UID:\$TARGET_UID, GID:\$TARGET_GID)"
# ALWAYS remove storage system metadata to prevent corruption issues
# This is safe - storage system recreates it automatically
# User data (files) are NOT in .minio.sys, they're safe
if [ -d "/app/server/minio-data/.minio.sys" ]; then
echo " 🧹 Cleaning storage system metadata (safe, auto-regenerated)..."
rm -rf /app/server/minio-data/.minio.sys 2>/dev/null || true
fi
# SMART CHOWN: Only run expensive recursive chown when UID/GID changed
# This dramatically speeds up subsequent starts
UIDGID_MARKER="/app/server/.palmr-uidgid"
CURRENT_OWNER="\$TARGET_UID:\$TARGET_GID"
NEEDS_CHOWN=false
if [ -f "\$UIDGID_MARKER" ]; then
STORED_OWNER=\$(cat "\$UIDGID_MARKER" 2>/dev/null || echo "")
if [ "\$STORED_OWNER" != "\$CURRENT_OWNER" ]; then
echo " 📝 UID/GID changed (\$STORED_OWNER → \$CURRENT_OWNER)"
NEEDS_CHOWN=true
else
echo " ✓ UID/GID unchanged (\$CURRENT_OWNER), skipping chown"
fi
else
echo " 📝 First run or marker missing, will set ownership"
NEEDS_CHOWN=true
fi
if [ "\$NEEDS_CHOWN" = "true" ]; then
echo " 🔧 Setting ownership (this may take a moment on first run)..."
# Only chown the directories that need it
chown \$TARGET_UID:\$TARGET_GID /app/server 2>/dev/null || true
# For most directories, just chown the directory itself (fast)
for dir in uploads temp-uploads; do
if [ -d "/app/server/\$dir" ]; then
chown \$TARGET_UID:\$TARGET_GID "/app/server/\$dir" 2>/dev/null || true
fi
done
# For prisma directory, we need recursive chown for database files
if [ -d "/app/server/prisma" ]; then
echo " 🔧 Fixing database permissions..."
chown -R \$TARGET_UID:\$TARGET_GID "/app/server/prisma" 2>/dev/null || true
fi
# For minio-data, we NEED recursive chown because MinIO creates subdirectories
# and needs write access to all of them
if [ -d "/app/server/minio-data" ]; then
echo " 🔧 Fixing MinIO storage permissions..."
chown -R \$TARGET_UID:\$TARGET_GID "/app/server/minio-data" 2>/dev/null || true
fi
# Save current UID/GID to marker
echo "\$CURRENT_OWNER" > "\$UIDGID_MARKER"
chown \$TARGET_UID:\$TARGET_GID "\$UIDGID_MARKER" 2>/dev/null || true
echo " ✅ Ownership updated and cached"
fi
chmod 755 /app/server 2>/dev/null || echo " ⚠️ chmod skipped"
# Verify critical directories are writable
if touch /app/server/.test-write 2>/dev/null; then
rm -f /app/server/.test-write
echo " ✅ Storage directory is writable"
else
echo " ❌ FATAL: /app/server is NOT writable!"
echo " Check Docker volume permissions"
ls -la /app/server 2>/dev/null || true
fi
echo "✅ Storage ready, starting services..."
# Start supervisor
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
EOF
RUN chmod +x /app/start.sh
# Create volume mount points for bind mounts
VOLUME ["/app/server"]
# Expose ports
EXPOSE 3333 5487 9379 9378
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:5487 || exit 1
# Start application
CMD ["/app/start.sh"]