| |
| |
|
|
| |
| |
| |
| FROM node:18-alpine as frontend-builder |
|
|
| |
| WORKDIR /app |
|
|
| |
| COPY client/package*.json ./ |
|
|
| |
| RUN npm ci --only=production && \ |
| npm cache clean --force |
|
|
| |
| COPY client/ ./ |
|
|
| |
| RUN npm run build |
|
|
| |
| |
| |
| FROM node:18-alpine as backend-builder |
|
|
| WORKDIR /app |
|
|
| |
| COPY server/package*.json ./ |
|
|
| |
| RUN npm ci --only=production && \ |
| npm cache clean --force |
|
|
| |
| COPY server/ ./ |
|
|
| |
| |
| |
| FROM node:18-alpine |
|
|
| |
| RUN apk add --no-cache \ |
| nginx \ |
| supervisor \ |
| wget \ |
| curl \ |
| dumb-init \ |
| && rm -rf /var/cache/apk/* |
|
|
| |
| RUN addgroup -g 1001 -S appuser && \ |
| adduser -S appuser -u 1001 -G appuser |
|
|
| |
| RUN mkdir -p /app /var/log/nginx /var/log/supervisor /run/nginx && \ |
| chown -R appuser:appuser /app /var/log/nginx /var/log/supervisor /run/nginx |
|
|
| |
| WORKDIR /app |
|
|
| |
| COPY --from=backend-builder --chown=appuser:appuser /app ./ |
|
|
| |
| COPY --from=frontend-builder --chown=appuser:appuser /app/dist ./public |
|
|
| |
| COPY --chown=appuser:appuser <<EOF /etc/nginx/nginx.conf |
| user appuser; |
| worker_processes auto; |
| pid /run/nginx/nginx.pid; |
|
|
| events { |
| worker_connections 1024; |
| use epoll; |
| multi_accept on; |
| } |
|
|
| http { |
| include /etc/nginx/mime.types; |
| default_type application/octet-stream; |
| |
| |
| log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" ' |
| '\$status \$body_bytes_sent "\$http_referer" ' |
| '"\$http_user_agent" "\$http_x_forwarded_for"'; |
| |
| access_log /var/log/nginx/access.log main; |
| error_log /var/log/nginx/error.log warn; |
| |
| |
| sendfile on; |
| tcp_nopush on; |
| tcp_nodelay on; |
| keepalive_timeout 65; |
| types_hash_max_size 2048; |
| |
| |
| gzip on; |
| gzip_vary on; |
| gzip_min_length 1024; |
| gzip_comp_level 6; |
| gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; |
| |
| server { |
| listen 80; |
| server_name localhost; |
| root /app/public; |
| index index.html; |
| |
| |
| location / { |
| try_files \$uri \$uri/ /index.html; |
| } |
| |
| |
| location /api/ { |
| proxy_pass http://127.0.0.1:5000; |
| proxy_http_version 1.1; |
| proxy_set_header Upgrade \$http_upgrade; |
| proxy_set_header Connection 'upgrade'; |
| proxy_set_header Host \$host; |
| proxy_set_header X-Real-IP \$remote_addr; |
| proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; |
| proxy_set_header X-Forwarded-Proto \$scheme; |
| proxy_cache_bypass \$http_upgrade; |
| } |
| |
| |
| location /socket.io/ { |
| proxy_pass http://127.0.0.1:5000; |
| proxy_http_version 1.1; |
| proxy_set_header Upgrade \$http_upgrade; |
| proxy_set_header Connection "upgrade"; |
| proxy_set_header Host \$host; |
| proxy_set_header X-Real-IP \$remote_addr; |
| proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; |
| proxy_set_header X-Forwarded-Proto \$scheme; |
| } |
| |
| |
| location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)\$ { |
| expires 1y; |
| add_header Cache-Control "public, immutable"; |
| } |
| } |
| } |
| EOF |
|
|
| |
| COPY --chown=appuser:appuser <<EOF /etc/supervisor/conf.d/supervisord.conf |
| [supervisord] |
| nodaemon=true |
| user=appuser |
| logfile=/var/log/supervisor/supervisord.log |
| pidfile=/run/supervisord.pid |
| childlogdir=/var/log/supervisor |
|
|
| [program:nginx] |
| command=nginx -g "daemon off;" |
| autostart=true |
| autorestart=true |
| stderr_logfile=/var/log/supervisor/nginx_error.log |
| stdout_logfile=/var/log/supervisor/nginx_access.log |
| user=appuser |
|
|
| [program:node] |
| command=node index.js |
| directory=/app |
| autostart=true |
| autorestart=true |
| stderr_logfile=/var/log/supervisor/node_error.log |
| stdout_logfile=/var/log/supervisor/node_access.log |
| user=appuser |
| environment=NODE_ENV=production,PORT=5000 |
| EOF |
|
|
| |
| RUN chown -R appuser:appuser /etc/nginx /etc/supervisor |
|
|
| |
| USER appuser |
|
|
| |
| EXPOSE 80 |
|
|
| |
| ENV NODE_ENV=production |
| ENV PORT=5000 |
|
|
| |
| HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ |
| CMD wget --no-verbose --tries=1 --spider http://localhost:80/api/health || exit 1 |
|
|
| |
| ENTRYPOINT ["/usr/bin/dumb-init", "--"] |
|
|
| |
| CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] |
|
|