From 1e70525f737ad6172cfa631c05f0cac897ae150c Mon Sep 17 00:00:00 2001 From: myrmidex Date: Tue, 12 Aug 2025 12:17:27 +0200 Subject: [PATCH] Fix prod scripts --- docker/production/Dockerfile | 28 +++++----- docker/production/docker-compose.yml | 79 ++++------------------------ docker/production/nginx.conf | 55 +++++++++++-------- docker/production/start-app.sh | 16 +++--- docker/production/supervisord.conf | 22 +++++++- 5 files changed, 89 insertions(+), 111 deletions(-) diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile index 6383c51..8690f35 100644 --- a/docker/production/Dockerfile +++ b/docker/production/Dockerfile @@ -3,17 +3,14 @@ FROM node:22-alpine AS frontend-builder WORKDIR /app -# Copy package files -COPY package*.json ./ +# Copy frontend package files +COPY frontend/package*.json ./ # Install Node dependencies RUN npm ci # Copy frontend source -COPY resources/ resources/ -COPY public/ public/ -COPY vite.config.js ./ -COPY tsconfig.json ./ +COPY frontend/ ./ # Build frontend assets RUN npm run build @@ -55,14 +52,18 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # Set working directory WORKDIR /var/www/html -# Copy application code first +# Copy application code COPY . . -# Install PHP dependencies after copying all files +# Install PHP dependencies in backend directory +WORKDIR /var/www/html/backend RUN composer install --no-dev --optimize-autoloader --no-interaction -# Copy built frontend assets from builder stage -COPY --from=frontend-builder /app/public/build/ ./public/build/ +# Copy built frontend assets from builder stage to frontend dist +COPY --from=frontend-builder /app/dist/ /var/www/html/frontend/dist/ + +# Back to main directory +WORKDIR /var/www/html # Copy nginx and supervisor configurations COPY docker/production/nginx.conf /etc/nginx/http.d/default.conf @@ -70,8 +71,9 @@ COPY docker/production/supervisord.conf /etc/supervisord.conf COPY docker/production/start-app.sh /usr/local/bin/start-app # Set proper permissions -RUN chown -R www-data:www-data storage bootstrap/cache public/build \ - && chmod -R 755 storage bootstrap/cache \ +RUN chown -R www-data:www-data /var/www/html \ + && chmod -R 755 /var/www/html/backend/storage \ + && chmod -R 755 /var/www/html/backend/bootstrap/cache \ && chmod +x /usr/local/bin/start-app # Expose port 80 for nginx @@ -79,7 +81,7 @@ EXPOSE 80 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ - CMD php artisan --version || exit 1 + CMD cd /var/www/html/backend && php artisan --version || exit 1 # Start the application CMD ["/usr/local/bin/start-app"] \ No newline at end of file diff --git a/docker/production/docker-compose.yml b/docker/production/docker-compose.yml index df35b49..f21c69c 100644 --- a/docker/production/docker-compose.yml +++ b/docker/production/docker-compose.yml @@ -1,27 +1,26 @@ services: app: - image: codeberg.org/lvl0/ffr:latest -# build: -# context: ../.. -# dockerfile: docker/production/Dockerfile + image: codeberg.org/lvl0/ffr:v1.0.0-rc1 container_name: ffr-app restart: unless-stopped - working_dir: /var/www/html environment: - APP_ENV=production - APP_DEBUG=false + - APP_KEY=${APP_KEY} + - APP_URL=${APP_URL} - DB_CONNECTION=mysql - DB_HOST=db - DB_PORT=3306 - DB_DATABASE=ffr - DB_USERNAME=ffr_user - - DB_PASSWORD=ffr_password + - DB_PASSWORD=${DB_PASSWORD} - REDIS_HOST=redis - REDIS_PORT=6379 - CACHE_DRIVER=redis - SESSION_DRIVER=redis - QUEUE_CONNECTION=redis - volumes: [] + - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} + - TELEGRAM_CHANNEL_ID=${TELEGRAM_CHANNEL_ID} ports: - "8000:80" depends_on: @@ -32,62 +31,6 @@ services: networks: - ffr-network - queue: - image: codeberg.org/lvl0/ffr:latest - container_name: ffr-queue - restart: unless-stopped - working_dir: /var/www/html - environment: - - APP_ENV=production - - APP_DEBUG=false - - DB_CONNECTION=mysql - - DB_HOST=db - - DB_PORT=3306 - - DB_DATABASE=ffr - - DB_USERNAME=ffr_user - - DB_PASSWORD=ffr_password - - REDIS_HOST=redis - - REDIS_PORT=6379 - - CACHE_DRIVER=redis - - SESSION_DRIVER=redis - - QUEUE_CONNECTION=redis - command: ["php", "artisan", "horizon"] - depends_on: - db: - condition: service_healthy - redis: - condition: service_started - networks: - - ffr-network - - scheduler: - image: codeberg.org/lvl0/ffr:latest - container_name: ffr-scheduler - restart: unless-stopped - working_dir: /var/www/html - environment: - - APP_ENV=production - - APP_DEBUG=false - - DB_CONNECTION=mysql - - DB_HOST=db - - DB_PORT=3306 - - DB_DATABASE=ffr - - DB_USERNAME=ffr_user - - DB_PASSWORD=ffr_password - - REDIS_HOST=redis - - REDIS_PORT=6379 - - CACHE_DRIVER=redis - - SESSION_DRIVER=redis - - QUEUE_CONNECTION=redis - command: ["sh", "-c", "while true; do php artisan schedule:run --verbose --no-interaction; sleep 60; done"] - depends_on: - db: - condition: service_healthy - redis: - condition: service_started - networks: - - ffr-network - db: image: docker.io/library/mysql:8.4 container_name: ffr-db @@ -95,14 +38,12 @@ services: environment: - MYSQL_DATABASE=ffr - MYSQL_USER=ffr_user - - MYSQL_PASSWORD=ffr_password - - MYSQL_ROOT_PASSWORD=root_password + - MYSQL_PASSWORD=${DB_PASSWORD} + - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} volumes: - db_data:/var/lib/mysql - ports: - - "3306:3306" healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "ffr_user", "-pffr_password"] + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "ffr_user", "-p${DB_PASSWORD}"] timeout: 5s retries: 5 interval: 3s @@ -127,4 +68,4 @@ volumes: db_data: driver: local redis_data: - driver: local \ No newline at end of file + driver: local diff --git a/docker/production/nginx.conf b/docker/production/nginx.conf index 393969c..5ff7994 100644 --- a/docker/production/nginx.conf +++ b/docker/production/nginx.conf @@ -1,22 +1,19 @@ server { listen 80; server_name localhost; - root /var/www/html/public; - index index.php index.html; + + # Serve static React build files + root /var/www/html/frontend/dist; + index index.html; - # Security headers - add_header X-Frame-Options "SAMEORIGIN"; - add_header X-Content-Type-Options "nosniff"; - add_header X-XSS-Protection "1; mode=block"; - - location / { - try_files $uri $uri/ /index.php?$query_string; - } - - location ~ \.php$ { + # API requests to Laravel backend + location /api/ { + root /var/www/html/backend/public; + try_files /index.php =404; + fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param SCRIPT_FILENAME /var/www/html/backend/public/index.php; include fastcgi_params; # Increase timeouts for long-running requests @@ -24,6 +21,30 @@ server { fastcgi_send_timeout 300; } + # Serve Laravel public assets (images, etc.) + location /images/ { + alias /var/www/html/backend/public/images/; + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # React app - catch all routes + location / { + try_files $uri $uri/ /index.html; + } + + # Static assets with far-future expiry + location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # Security headers + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + add_header X-XSS-Protection "1; mode=block"; + # Deny access to hidden files location ~ /\.ht { deny all; @@ -34,14 +55,6 @@ server { deny all; } - # Static assets with far-future expiry - location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - access_log off; - } - - # Laravel specific optimizations location = /favicon.ico { access_log off; log_not_found off; diff --git a/docker/production/start-app.sh b/docker/production/start-app.sh index 1819690..f6255c9 100644 --- a/docker/production/start-app.sh +++ b/docker/production/start-app.sh @@ -1,8 +1,8 @@ #!/bin/sh # Create .env file if it doesn't exist -if [ ! -f /var/www/html/.env ]; then - cp /var/www/html/.env.example /var/www/html/.env 2>/dev/null || touch /var/www/html/.env +if [ ! -f /var/www/html/backend/.env ]; then + cp /var/www/html/backend/.env.example /var/www/html/backend/.env 2>/dev/null || touch /var/www/html/backend/.env fi # Wait for database to be ready @@ -14,21 +14,23 @@ done echo "Database connection established!" # Generate app key if not set -if ! grep -q "APP_KEY=base64:" /var/www/html/.env; then - php artisan key:generate --force +if ! grep -q "APP_KEY=base64:" /var/www/html/backend/.env; then + cd /var/www/html/backend && php artisan key:generate --force fi # Laravel optimizations for production +cd /var/www/html/backend php artisan config:cache php artisan route:cache php artisan view:cache # Run migrations +cd /var/www/html/backend php artisan migrate --force -# Run seeders (only if needed for production data) -php artisan db:seed --force --class=PlatformInstanceSeeder -php artisan db:seed --force --class=SettingsSeeder +# Run all seeders (same as dev) +cd /var/www/html/backend +php artisan db:seed --force # Start supervisor to manage nginx and php-fpm supervisord -c /etc/supervisord.conf \ No newline at end of file diff --git a/docker/production/supervisord.conf b/docker/production/supervisord.conf index 209c706..5df63d5 100644 --- a/docker/production/supervisord.conf +++ b/docker/production/supervisord.conf @@ -22,4 +22,24 @@ stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 -priority=10 \ No newline at end of file +priority=10 + +[program:horizon] +command=php /var/www/html/backend/artisan horizon +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +priority=20 + +[program:scheduler] +command=sh -c "while true; do php /var/www/html/backend/artisan schedule:run --verbose --no-interaction; sleep 60; done" +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +priority=20 \ No newline at end of file