Sughan-0077 commited on
Commit
91c0e7f
·
1 Parent(s): fe1a2e0

Fix permissions and robust multi-service startup for HF Spaces

Browse files
Files changed (3) hide show
  1. Dockerfile +41 -67
  2. start.sh +11 -9
  3. supervisord.conf +0 -2
Dockerfile CHANGED
@@ -1,93 +1,67 @@
1
  # ─────────────────────────────────────────────────────────────────
2
- # Taskflow — All-in-one Dockerfile for Hugging Face Spaces
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
- ENV DEBIAN_FRONTEND=noninteractive
20
- ENV NODE_ENV=production
21
- ENV PORT=5000
22
- ENV DB_HOST=127.0.0.1
23
- ENV DB_PORT=5432
24
- ENV DB_NAME=taskflow
25
- ENV DB_USER=taskflow_user
26
- ENV DB_PASSWORD=taskflow_hf_secret
27
- ENV JWT_SECRET=taskflow_huggingface_jwt_secret_change_for_production_use
28
- ENV JWT_EXPIRES_IN=7d
29
- ENV FRONTEND_URL=http://localhost:7860
30
-
31
- # ── System packages ────────────────────────────────────────────────
 
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
- && rm -rf /var/lib/apt/lists/*
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
- # ── Backend ────────────────────────────────────────────────────────
49
- COPY backend/package*.json /app/backend/
50
  RUN cd /app/backend && npm ci --only=production
51
 
52
- COPY backend/ /app/backend/
53
 
54
- # ── Frontend — build React app ─────────────────────────────────────
55
- COPY frontend/package*.json /app/frontend/
56
  RUN cd /app/frontend && npm ci
57
 
58
- COPY frontend/ /app/frontend/
59
- # Point the API at the same origin so nginx can proxy it
60
- RUN echo "REACT_APP_API_URL=/api" > /app/frontend/.env.production
61
- RUN cd /app/frontend && npm run build
62
 
63
- # ── Nginx config ───────────────────────────────────────────────────
64
  RUN rm -f /etc/nginx/sites-enabled/default
65
- COPY hf.nginx.conf /etc/nginx/sites-enabled/taskflow.conf
66
-
67
- # ── Supervisord config ─────────────────────────────────────────────
68
- COPY supervisord.conf /etc/supervisor/conf.d/taskflow.conf
69
 
70
- # ── Startup script ─────────────────────────────────────────────────
71
- COPY start.sh /app/start.sh
72
- RUN chmod +x /app/start.sh
73
 
74
- # ── HF Spaces: must run as non-root with uid 1000 ──────────────────
75
- RUN useradd -m -u 1000 hfuser \
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
- # initdb must run as postgres user
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
- su -c "/usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/data -l /tmp/pg_setup.log start -w" postgres
19
 
20
  # Wait for postgres to be ready
21
  for i in {1..20}; do
22
- if su -c "pg_isready -h 127.0.0.1 -U postgres" postgres >/dev/null 2>&1; then
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
- su -c "psql -h 127.0.0.1 -U postgres -tc \"SELECT 1 FROM pg_roles WHERE rolname='taskflow_user'\" | grep -q 1 || psql -h 127.0.0.1 -U postgres -c \"CREATE USER taskflow_user WITH PASSWORD 'taskflow_hf_secret';\"" postgres
33
- su -c "psql -h 127.0.0.1 -U postgres -tc \"SELECT 1 FROM pg_database WHERE datname='taskflow'\" | grep -q 1 || psql -h 127.0.0.1 -U postgres -c \"CREATE DATABASE taskflow OWNER taskflow_user;\"" postgres
34
- su -c "psql -h 127.0.0.1 -U postgres -c \"GRANT ALL PRIVILEGES ON DATABASE taskflow TO taskflow_user;\"" postgres
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=$(su -c "psql -h 127.0.0.1 -U postgres -d taskflow -tAc \"SELECT COUNT(*) FROM users 2>/dev/null || echo 0\"" postgres 2>/dev/null || echo "0")
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
- su -c "/usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/data stop -m fast" postgres || true
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