Spaces:
Running
Running
Commit ·
91c0e7f
1
Parent(s): fe1a2e0
Fix permissions and robust multi-service startup for HF Spaces
Browse files- Dockerfile +41 -67
- start.sh +11 -9
- supervisord.conf +0 -2
Dockerfile
CHANGED
|
@@ -1,93 +1,67 @@
|
|
| 1 |
# ─────────────────────────────────────────────────────────────────
|
| 2 |
-
# Taskflow —
|
| 3 |
-
#
|
| 4 |
-
# HF Spaces rules this file must satisfy:
|
| 5 |
-
# - Expose exactly port 7860
|
| 6 |
-
# - Run as non-root user (we use "user" uid 1000)
|
| 7 |
-
# - Single container (no docker-compose)
|
| 8 |
-
#
|
| 9 |
-
# Architecture inside this container:
|
| 10 |
-
# PostgreSQL 16 → internal port 5432
|
| 11 |
-
# Node/Express → internal port 5000
|
| 12 |
-
# Nginx → port 7860 (serves React SPA + proxies /api to Express)
|
| 13 |
-
#
|
| 14 |
-
# Process manager: supervisord keeps all three services alive.
|
| 15 |
# ─────────────────────────────────────────────────────────────────
|
| 16 |
|
| 17 |
FROM ubuntu:22.04
|
| 18 |
|
| 19 |
-
|
| 20 |
-
ENV
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
| 32 |
RUN apt-get update && apt-get install -y \
|
| 33 |
curl wget gnupg2 lsb-release ca-certificates \
|
| 34 |
nginx supervisor \
|
| 35 |
postgresql-14 postgresql-client-14 \
|
| 36 |
-
&&
|
| 37 |
-
|
| 38 |
-
# ── Node.js 20 ─────────────────────────────────────────────────────
|
| 39 |
-
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
| 40 |
&& apt-get install -y nodejs \
|
| 41 |
-
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
-
# ── Working directories ────────────────────────────────────────────
|
| 44 |
WORKDIR /app
|
| 45 |
-
RUN mkdir -p /app/backend /app/frontend /var/log/supervisor \
|
| 46 |
-
/run/postgresql /var/lib/postgresql/data
|
| 47 |
|
| 48 |
-
#
|
| 49 |
-
COPY backend/package*.json /app/backend/
|
| 50 |
RUN cd /app/backend && npm ci --only=production
|
| 51 |
|
| 52 |
-
COPY backend/ /app/backend/
|
| 53 |
|
| 54 |
-
#
|
| 55 |
-
COPY frontend/package*.json /app/frontend/
|
| 56 |
RUN cd /app/frontend && npm ci
|
| 57 |
|
| 58 |
-
COPY frontend/ /app/frontend/
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
RUN cd /app/frontend && npm run build
|
| 62 |
|
| 63 |
-
#
|
| 64 |
RUN rm -f /etc/nginx/sites-enabled/default
|
| 65 |
-
COPY hf.nginx.conf /etc/nginx/sites-enabled/taskflow.conf
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
COPY supervisord.conf /etc/supervisor/conf.d/taskflow.conf
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
RUN chmod +x /app/start.sh
|
| 73 |
|
| 74 |
-
#
|
| 75 |
-
RUN
|
| 76 |
-
&& chown -R hfuser:hfuser /app \
|
| 77 |
-
&& chown -R hfuser:hfuser /var/log/nginx \
|
| 78 |
-
&& chown -R hfuser:hfuser /var/lib/nginx \
|
| 79 |
-
&& chown -R hfuser:hfuser /run \
|
| 80 |
-
&& chown -R postgres:postgres /var/lib/postgresql \
|
| 81 |
-
&& chown -R postgres:postgres /run/postgresql \
|
| 82 |
-
&& chmod 777 /var/log/supervisor \
|
| 83 |
-
&& chmod 777 /tmp
|
| 84 |
-
|
| 85 |
-
# Nginx needs to write to these as non-root
|
| 86 |
-
RUN chown -R hfuser:hfuser /var/log/nginx /var/lib/nginx /run/nginx* 2>/dev/null || true \
|
| 87 |
-
&& touch /run/nginx.pid && chown hfuser:hfuser /run/nginx.pid 2>/dev/null || true
|
| 88 |
|
| 89 |
USER hfuser
|
| 90 |
-
|
| 91 |
EXPOSE 7860
|
| 92 |
-
|
| 93 |
CMD ["/app/start.sh"]
|
|
|
|
| 1 |
# ─────────────────────────────────────────────────────────────────
|
| 2 |
+
# Taskflow — Robust Multi-Service Dockerfile for HF Spaces
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
# ─────────────────────────────────────────────────────────────────
|
| 4 |
|
| 5 |
FROM ubuntu:22.04
|
| 6 |
|
| 7 |
+
# Environment variables
|
| 8 |
+
ENV DEBIAN_FRONTEND=noninteractive \
|
| 9 |
+
NODE_ENV=production \
|
| 10 |
+
PORT=5000 \
|
| 11 |
+
DB_HOST=127.0.0.1 \
|
| 12 |
+
DB_PORT=5432 \
|
| 13 |
+
DB_NAME=taskflow \
|
| 14 |
+
DB_USER=taskflow_user \
|
| 15 |
+
DB_PASSWORD=taskflow_hf_secret \
|
| 16 |
+
JWT_SECRET=taskflow_huggingface_jwt_secret_change_for_production_use \
|
| 17 |
+
JWT_EXPIRES_IN=7d \
|
| 18 |
+
FRONTEND_URL=http://localhost:7860
|
| 19 |
+
|
| 20 |
+
# 1. Install System Dependencies
|
| 21 |
RUN apt-get update && apt-get install -y \
|
| 22 |
curl wget gnupg2 lsb-release ca-certificates \
|
| 23 |
nginx supervisor \
|
| 24 |
postgresql-14 postgresql-client-14 \
|
| 25 |
+
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
|
|
|
|
|
|
|
|
|
| 26 |
&& apt-get install -y nodejs \
|
| 27 |
+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
| 28 |
+
|
| 29 |
+
# 2. Setup User and Directories
|
| 30 |
+
# HF Spaces uses UID 1000
|
| 31 |
+
RUN useradd -m -u 1000 hfuser && \
|
| 32 |
+
mkdir -p /app/backend /app/frontend /var/log/supervisor /var/run/supervisor \
|
| 33 |
+
/run/postgresql /var/lib/postgresql/data /var/log/nginx /var/lib/nginx /run/nginx \
|
| 34 |
+
&& chown -R hfuser:hfuser /app /var/log/supervisor /var/run/supervisor /run/postgresql \
|
| 35 |
+
/var/lib/postgresql /var/log/nginx /var/lib/nginx /run/nginx
|
| 36 |
|
|
|
|
| 37 |
WORKDIR /app
|
|
|
|
|
|
|
| 38 |
|
| 39 |
+
# 3. Backend Implementation
|
| 40 |
+
COPY --chown=hfuser:hfuser backend/package*.json /app/backend/
|
| 41 |
RUN cd /app/backend && npm ci --only=production
|
| 42 |
|
| 43 |
+
COPY --chown=hfuser:hfuser backend/ /app/backend/
|
| 44 |
|
| 45 |
+
# 4. Frontend Implementation
|
| 46 |
+
COPY --chown=hfuser:hfuser frontend/package*.json /app/frontend/
|
| 47 |
RUN cd /app/frontend && npm ci
|
| 48 |
|
| 49 |
+
COPY --chown=hfuser:hfuser frontend/ /app/frontend/
|
| 50 |
+
RUN echo "REACT_APP_API_URL=/api" > /app/frontend/.env.production && \
|
| 51 |
+
cd /app/frontend && npm run build
|
|
|
|
| 52 |
|
| 53 |
+
# 5. Configurations
|
| 54 |
RUN rm -f /etc/nginx/sites-enabled/default
|
| 55 |
+
COPY --chown=hfuser:hfuser hf.nginx.conf /etc/nginx/sites-enabled/taskflow.conf
|
| 56 |
+
COPY --chown=hfuser:hfuser supervisord.conf /etc/supervisor/conf.d/taskflow.conf
|
| 57 |
+
COPY --chown=hfuser:hfuser start.sh /app/start.sh
|
|
|
|
| 58 |
|
| 59 |
+
RUN chmod +x /app/start.sh && \
|
| 60 |
+
touch /run/nginx.pid && chown hfuser:hfuser /run/nginx.pid
|
|
|
|
| 61 |
|
| 62 |
+
# 6. Final Permissions Check
|
| 63 |
+
RUN chmod -R 777 /var/run /run /tmp /var/log/supervisor /var/lib/postgresql
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
USER hfuser
|
|
|
|
| 66 |
EXPOSE 7860
|
|
|
|
| 67 |
CMD ["/app/start.sh"]
|
start.sh
CHANGED
|
@@ -5,21 +5,23 @@ echo "========================================"
|
|
| 5 |
echo " Taskflow — HF Spaces Startup"
|
| 6 |
echo "========================================"
|
| 7 |
|
|
|
|
|
|
|
|
|
|
| 8 |
# ── 1. Initialise PostgreSQL data directory ────────────────────────
|
| 9 |
if [ ! -f /var/lib/postgresql/data/PG_VERSION ]; then
|
| 10 |
echo "▶ Initialising PostgreSQL data directory..."
|
| 11 |
-
|
| 12 |
-
su -c "/usr/lib/postgresql/14/bin/initdb -D /var/lib/postgresql/data --auth=trust --username=postgres" postgres
|
| 13 |
echo " Done."
|
| 14 |
fi
|
| 15 |
|
| 16 |
# ── 2. Start PostgreSQL temporarily to set up DB + user ────────────
|
| 17 |
echo "▶ Starting PostgreSQL for setup..."
|
| 18 |
-
|
| 19 |
|
| 20 |
# Wait for postgres to be ready
|
| 21 |
for i in {1..20}; do
|
| 22 |
-
if
|
| 23 |
echo " PostgreSQL is ready."
|
| 24 |
break
|
| 25 |
fi
|
|
@@ -29,9 +31,9 @@ done
|
|
| 29 |
|
| 30 |
# ── 3. Create database and user if they don't exist ────────────────
|
| 31 |
echo "▶ Setting up database..."
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
echo " Database ready."
|
| 36 |
|
| 37 |
# ── 4. Run migrations ──────────────────────────────────────────────
|
|
@@ -41,7 +43,7 @@ node src/utils/migrate.js
|
|
| 41 |
echo " Migrations complete."
|
| 42 |
|
| 43 |
# ── 5. Seed demo data (only if users table is empty) ───────────────
|
| 44 |
-
USER_COUNT=$(
|
| 45 |
if [ "$USER_COUNT" = "0" ] || [ -z "$USER_COUNT" ]; then
|
| 46 |
echo "▶ Seeding demo data..."
|
| 47 |
node src/utils/seed.js || echo " Seed skipped (already exists)."
|
|
@@ -51,7 +53,7 @@ fi
|
|
| 51 |
|
| 52 |
# ── 6. Stop the temporary postgres (supervisord will restart it) ───
|
| 53 |
echo "▶ Handing off PostgreSQL to supervisord..."
|
| 54 |
-
|
| 55 |
|
| 56 |
# ── 7. Hand off to supervisord ────────────────────────────────────
|
| 57 |
echo "▶ Starting all services via supervisord..."
|
|
|
|
| 5 |
echo " Taskflow — HF Spaces Startup"
|
| 6 |
echo "========================================"
|
| 7 |
|
| 8 |
+
# Pre-cleanup to ensure fresh start if restarted
|
| 9 |
+
rm -rf /tmp/pg_setup.log /run/postgresql/*.pid /run/nginx.pid 2>/dev/null || true
|
| 10 |
+
|
| 11 |
# ── 1. Initialise PostgreSQL data directory ────────────────────────
|
| 12 |
if [ ! -f /var/lib/postgresql/data/PG_VERSION ]; then
|
| 13 |
echo "▶ Initialising PostgreSQL data directory..."
|
| 14 |
+
/usr/lib/postgresql/14/bin/initdb -D /var/lib/postgresql/data --auth=trust --username=hfuser
|
|
|
|
| 15 |
echo " Done."
|
| 16 |
fi
|
| 17 |
|
| 18 |
# ── 2. Start PostgreSQL temporarily to set up DB + user ────────────
|
| 19 |
echo "▶ Starting PostgreSQL for setup..."
|
| 20 |
+
/usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/data -l /tmp/pg_setup.log start -w
|
| 21 |
|
| 22 |
# Wait for postgres to be ready
|
| 23 |
for i in {1..20}; do
|
| 24 |
+
if pg_isready -h 127.0.0.1 -U hfuser >/dev/null 2>&1; then
|
| 25 |
echo " PostgreSQL is ready."
|
| 26 |
break
|
| 27 |
fi
|
|
|
|
| 31 |
|
| 32 |
# ── 3. Create database and user if they don't exist ────────────────
|
| 33 |
echo "▶ Setting up database..."
|
| 34 |
+
psql -h 127.0.0.1 -U hfuser -d postgres -tc "SELECT 1 FROM pg_roles WHERE rolname='taskflow_user'" | grep -q 1 || psql -h 127.0.0.1 -U hfuser -d postgres -c "CREATE USER taskflow_user WITH PASSWORD 'taskflow_hf_secret';"
|
| 35 |
+
psql -h 127.0.0.1 -U hfuser -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='taskflow'" | grep -q 1 || psql -h 127.0.0.1 -U hfuser -d postgres -c "CREATE DATABASE taskflow OWNER taskflow_user;"
|
| 36 |
+
psql -h 127.0.0.1 -U hfuser -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE taskflow TO taskflow_user;"
|
| 37 |
echo " Database ready."
|
| 38 |
|
| 39 |
# ── 4. Run migrations ──────────────────────────────────────────────
|
|
|
|
| 43 |
echo " Migrations complete."
|
| 44 |
|
| 45 |
# ── 5. Seed demo data (only if users table is empty) ───────────────
|
| 46 |
+
USER_COUNT=$(psql -h 127.0.0.1 -U hfuser -d taskflow -tAc "SELECT COUNT(*) FROM users 2>/dev/null || echo 0" 2>/dev/null || echo "0")
|
| 47 |
if [ "$USER_COUNT" = "0" ] || [ -z "$USER_COUNT" ]; then
|
| 48 |
echo "▶ Seeding demo data..."
|
| 49 |
node src/utils/seed.js || echo " Seed skipped (already exists)."
|
|
|
|
| 53 |
|
| 54 |
# ── 6. Stop the temporary postgres (supervisord will restart it) ───
|
| 55 |
echo "▶ Handing off PostgreSQL to supervisord..."
|
| 56 |
+
/usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/data stop -m fast || true
|
| 57 |
|
| 58 |
# ── 7. Hand off to supervisord ────────────────────────────────────
|
| 59 |
echo "▶ Starting all services via supervisord..."
|
supervisord.conf
CHANGED
|
@@ -2,11 +2,9 @@
|
|
| 2 |
nodaemon=true
|
| 3 |
logfile=/var/log/supervisor/supervisord.log
|
| 4 |
pidfile=/tmp/supervisord.pid
|
| 5 |
-
user=root
|
| 6 |
|
| 7 |
[program:postgres]
|
| 8 |
command=/usr/lib/postgresql/14/bin/postgres -D /var/lib/postgresql/data -c listen_addresses=127.0.0.1
|
| 9 |
-
user=postgres
|
| 10 |
autostart=true
|
| 11 |
autorestart=true
|
| 12 |
stdout_logfile=/var/log/supervisor/postgres.log
|
|
|
|
| 2 |
nodaemon=true
|
| 3 |
logfile=/var/log/supervisor/supervisord.log
|
| 4 |
pidfile=/tmp/supervisord.pid
|
|
|
|
| 5 |
|
| 6 |
[program:postgres]
|
| 7 |
command=/usr/lib/postgresql/14/bin/postgres -D /var/lib/postgresql/data -c listen_addresses=127.0.0.1
|
|
|
|
| 8 |
autostart=true
|
| 9 |
autorestart=true
|
| 10 |
stdout_logfile=/var/log/supervisor/postgres.log
|