forked from MansiVisuals/ViTransfer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-entrypoint.sh
More file actions
executable file
·265 lines (218 loc) · 8.4 KB
/
docker-entrypoint.sh
File metadata and controls
executable file
·265 lines (218 loc) · 8.4 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
264
265
#!/bin/bash
# ViTransfer Docker Entrypoint Script
# Universal compatibility: Works on Unraid, TrueNAS, Docker Desktop, Ubuntu, Podman
# Handles PUID/PGID remapping AND docker-compose user: directive
# This script runs automatically on container start - no manual intervention required
set -e
echo "ViTransfer starting..."
echo ""
# ========================================
# SMART USER DETECTION
# ========================================
# Detects how the container is running and adapts automatically:
# - Via docker-compose user: directive → Already correct user
# - Via PUID/PGID env vars → Remap user
# - Default → Use default UID 911
RUNNING_UID=$(id -u)
RUNNING_GID=$(id -g)
PUID=${PUID:-911}
PGID=${PGID:-911}
echo "[INFO] User Configuration:"
echo " Container running as: UID=$RUNNING_UID GID=$RUNNING_GID"
echo " Target (PUID/PGID): UID=$PUID GID=$PGID"
echo ""
# ========================================
# CASE 1: Already running as target user
# ========================================
if [ "$RUNNING_UID" = "$PUID" ] && [ "$RUNNING_GID" = "$PGID" ]; then
echo "[OK] Already running as target user UID:$PUID GID:$PGID"
echo " (Detected docker-compose 'user:' directive or matching PUID/PGID)"
echo ""
# Fix ownership of app files if needed (from build-time UID 911)
if [ "$RUNNING_UID" != "911" ]; then
echo "[SETUP] Fixing ownership of app files..."
# Only fix files still owned by build-time user (911)
# Don't touch mounted volumes!
find /app -maxdepth 2 \( -name '.next' -o -name 'public' -o -name 'node_modules' -o -name 'src' \) -user 911 \
-exec chown -R $RUNNING_UID:$RUNNING_GID {} + 2>/dev/null || true
echo "[OK] File ownership updated"
echo ""
fi
SKIP_SU_EXEC=true
# ========================================
# CASE 2: Running as non-root, but different UID
# ========================================
elif [ "$RUNNING_UID" != "0" ]; then
echo "[OK] Running as non-root user UID:$RUNNING_UID GID:$RUNNING_GID"
echo " (Container already secured, using current user)"
echo ""
# Fix ownership if possible (may fail without root, that's ok)
echo "[SETUP] Attempting to fix app file ownership..."
find /app -maxdepth 2 \( -name '.next' -o -name 'public' -o -name 'src' \) -user 911 \
-exec chown -R $RUNNING_UID:$RUNNING_GID {} + 2>/dev/null || true
echo "[OK] Ownership fix attempted (errors ignored)"
echo ""
SKIP_SU_EXEC=true
# ========================================
# CASE 3: Running as root - need to remap
# ========================================
else
echo "[SETUP] Running as root, remapping to UID:$PUID GID:$PGID..."
echo ""
# Get current app user IDs
CURRENT_UID=$(id -u app 2>/dev/null || echo "911")
CURRENT_GID=$(id -g app 2>/dev/null || echo "911")
# Only remap if needed
if [ "$CURRENT_UID" != "$PUID" ] || [ "$CURRENT_GID" != "$PGID" ]; then
# Update group ID if needed
if [ "$CURRENT_GID" != "$PGID" ]; then
groupmod -o -g "$PGID" app 2>/dev/null || true
fi
# Update user ID if needed
if [ "$CURRENT_UID" != "$PUID" ]; then
echo " Updating user permissions (this may take a moment...)"
usermod -o -u "$PUID" app 2>/dev/null || true
fi
# Fix ownership of internal app files only (not mounted volumes!)
chown -R app:app /app/.next /app/public /app/node_modules /app/src 2>/dev/null || true
echo "[OK] User permissions updated"
else
echo "[OK] User permissions already correct"
fi
echo ""
SKIP_SU_EXEC=false
fi
# ========================================
# SERVICE READINESS CHECKS
# ========================================
# Function to wait for postgres to be ready
wait_for_postgres() {
echo "[WAIT] Waiting for PostgreSQL to be ready..."
max_attempts=30
attempt=0
while [ $attempt -lt $max_attempts ]; do
if node -e "
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
prisma.\$connect()
.then(() => { console.log('Connected'); process.exit(0); })
.catch(() => { process.exit(1); });
" 2>/dev/null; then
echo "[OK] PostgreSQL is ready!"
return 0
fi
attempt=$((attempt + 1))
echo " Attempt $attempt/$max_attempts - waiting..."
sleep 2
done
echo "[ERROR] PostgreSQL is not ready after $max_attempts attempts"
return 1
}
# Function to wait for Redis to be ready
wait_for_redis() {
echo "[WAIT] Waiting for Redis to be ready..."
max_attempts=30
attempt=0
while [ $attempt -lt $max_attempts ]; do
if node -e "
const Redis = require('ioredis');
const redis = new Redis({
host: process.env.REDIS_HOST || 'redis',
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD || undefined,
maxRetriesPerRequest: 1,
retryStrategy: () => null
});
redis.ping()
.then(() => { redis.disconnect(); process.exit(0); })
.catch(() => { redis.disconnect(); process.exit(1); });
" 2>/dev/null; then
echo "[OK] Redis is ready!"
return 0
fi
attempt=$((attempt + 1))
echo " Attempt $attempt/$max_attempts - waiting..."
sleep 2
done
echo "[ERROR] Redis is not ready after $max_attempts attempts"
return 1
}
# Function to wait for app to be fully ready
wait_for_app() {
echo "[WAIT] Waiting for application to be fully ready..."
# Configurable hostname and port for different deployment scenarios
# APP_HOST: Container/service name (default: vitransfer-app)
# APP_PORT: Application port (default: 4321)
APP_HOST=${APP_HOST:-vitransfer-app}
APP_PORT=${APP_PORT:-4321}
max_attempts=150 # 5 minutes (150 attempts * 2 seconds)
attempt=0
echo " Checking: http://${APP_HOST}:${APP_PORT}/api/health"
while [ $attempt -lt $max_attempts ]; do
if curl -s -f http://${APP_HOST}:${APP_PORT}/api/health > /dev/null 2>&1; then
echo "[OK] Application is ready!"
return 0
fi
attempt=$((attempt + 1))
echo " Attempt $attempt/$max_attempts - waiting..."
sleep 2
done
echo "[ERROR] Application is not ready after $max_attempts attempts"
echo " Tried: http://${APP_HOST}:${APP_PORT}"
return 1
}
# ========================================
# DATABASE SETUP (MAIN APP ONLY)
# ========================================
# Only run migrations and initialization for the main app, not the worker
if [ "$1" = "npm" ] && [ "$2" = "start" ]; then
echo "[SETUP] Running database setup..."
echo ""
# Wait for services to be ready
wait_for_postgres
wait_for_redis
echo ""
echo "[DB] Running Prisma migrations..."
# Run migrations automatically
# - On first run: Creates all tables from scratch (initial_schema migration)
# - On updates: Applies only new migrations (e.g., when upgrading to v1.1, v1.2, etc.)
# - Idempotent: Safe to run multiple times, only applies pending migrations
if npx prisma migrate deploy; then
echo "[OK] Database migrations completed"
else
echo "[ERROR] Database migration failed"
exit 1
fi
echo ""
echo "[INIT] Database setup complete"
echo " Admin initialization will run automatically via instrumentation.ts"
echo ""
elif [[ "$@" == *"npm run worker"* ]] || [[ "$@" == *"worker"* ]]; then
echo "[SETUP] Worker initialization..."
echo ""
# Workers need to wait for database, Redis, AND the main app to be ready
wait_for_postgres
wait_for_redis
wait_for_app
echo ""
echo "[OK] All services ready for worker"
echo ""
fi
# ========================================
# START APPLICATION
# ========================================
echo "[START] Starting application..."
if [ "$SKIP_SU_EXEC" = "true" ]; then
echo " Running as: UID:$RUNNING_UID GID:$RUNNING_GID (direct)"
else
echo " Running as: UID:$PUID GID:$PGID (via su-exec app)"
fi
echo ""
# Execute the main command
if [ "$SKIP_SU_EXEC" = "true" ]; then
# Already running as correct user, no need for su-exec
exec "$@"
else
# Running as root, switch to app user
exec su-exec app "$@"
fi