diff --git a/.gitea/workflows/deploy-prod.yml b/.gitea/workflows/deploy-prod.yml index 42a4c23..9a09ef5 100644 --- a/.gitea/workflows/deploy-prod.yml +++ b/.gitea/workflows/deploy-prod.yml @@ -87,11 +87,11 @@ jobs: - name: Verify deployment run: | set -e - echo "Waiting for services to start..." - sleep 15 - cd "${DEPLOY_DIR}" + echo "Waiting for services to start..." + sleep 10 + for SERVICE in backend frontend; do STATUS=$(docker compose -f docker-compose.yml ps --status running --format '{{.Name}}' "$SERVICE" 2>/dev/null || true) if [ -z "$STATUS" ]; then @@ -110,15 +110,26 @@ jobs: echo "WARNING: Backend .env file not found" fi - if docker exec "$BE_CONTAINER" curl -sf http://localhost/health > /dev/null; then - echo "✓ Backend health check passed" - else - echo "WARNING: Backend health check failed" - fi + API_PORT=$(grep -E '^API_PORT=' .env 2>/dev/null | cut -d= -f2- | tr -d '"' || true) + FE_PORT=$(grep -E '^FE_PORT=' .env 2>/dev/null | cut -d= -f2- | tr -d '"' || true) + API_PORT=${API_PORT:-8080} + FE_PORT=${FE_PORT:-8081} - FE_CONTAINER=$(docker compose -f docker-compose.yml ps -q frontend) - if docker exec "$FE_CONTAINER" wget -q --spider http://localhost/; then - echo "✓ Frontend health check passed" - else - echo "WARNING: Frontend health check failed" - fi + check_health() { + NAME=$1 + URL=$2 + for i in 1 2 3 4 5 6; do + if curl -sf "$URL" > /dev/null; then + echo "✓ ${NAME} health check passed (${URL})" + return 0 + fi + echo "Waiting for ${NAME}... attempt ${i}/6" + sleep 5 + done + echo "ERROR: ${NAME} health check failed (${URL})" + docker compose -f docker-compose.yml logs --tail=50 "${NAME}" || true + return 1 + } + + check_health "backend" "http://127.0.0.1:${API_PORT}/health" + check_health "frontend" "http://127.0.0.1:${FE_PORT}/health" diff --git a/be/.env.production b/be/.env.production index 2919b12..18e4095 100644 --- a/be/.env.production +++ b/be/.env.production @@ -3,7 +3,7 @@ APP_ENV=production APP_KEY=base64:XdMAy5IbQMHsTrp1N7Tn/LIJC4SKenN8CfhYLt1s3tk= APP_DEBUG=false APP_TIMEZONE=Asia/Kuala_Lumpur -APP_URL=https://anggota.koppkb.com +APP_URL=https://api.koppkb.com APP_LOCALE=en APP_FALLBACK_LOCALE=en @@ -21,12 +21,13 @@ LOG_STACK=single LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=error -DB_CONNECTION=pgsql -DB_HOST=172.16.5.12 -DB_PORT=5433 +DB_CONNECTION=db +DB_HOST=db +DB_PORT=5432 DB_DATABASE=mykopkb DB_USERNAME=mykopkbuser DB_PASSWORD=MyKOPKB@Production_2026 +DB_ROOT_PASSWORD=MIq8ogpdKRppb5HThjY5Caeow5OFo8BCyJ SESSION_DRIVER=redis SESSION_LIFETIME=60 @@ -60,7 +61,7 @@ MAIL_HOST=mailpit MAIL_PORT=1025 MAIL_USERNAME=null MAIL_PASSWORD=null -MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_ADDRESS="noreply@koppkb.com" MAIL_FROM_NAME="${APP_NAME}" AWS_ACCESS_KEY_ID= @@ -91,7 +92,7 @@ EXTERNAL_API_BASE_URL= # SSO_ENABLE_FALLBACK=true # SSO_PROXY_ENABLED=true -SANCTUM_STATEFUL_DOMAINS=anggota.koppkb.com +SANCTUM_STATEFUL_DOMAINS=api.koppkb.com BLOCK_API_TOOLS_IN_PRODUCTION=true MIN_USER_AGENT_LENGTH=15 diff --git a/be/docker/production/docker-compose.production.yml b/be/docker/production/docker-compose.production.yml index f80b972..acb5bb6 100644 --- a/be/docker/production/docker-compose.production.yml +++ b/be/docker/production/docker-compose.production.yml @@ -44,7 +44,7 @@ services: networks: - mykopkb-production-network healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://localhost/"] + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1/health"] interval: 30s timeout: 10s retries: 3 @@ -60,7 +60,7 @@ services: container_name: mykopkb-postgres-production restart: unless-stopped ports: - - "${DB_PORT:-5432}:5432" + - "${DB_PORT:-5433}:5432" environment: - POSTGRES_ROOT_PASSWORD=${DB_ROOT_PASSWORD} - POSTGRES_DATABASE=${DB_DATABASE} diff --git a/be/docker/production/nginx/nginx.conf b/be/docker/production/nginx/nginx.conf index 0e5aa46..0135dd1 100644 --- a/be/docker/production/nginx/nginx.conf +++ b/be/docker/production/nginx/nginx.conf @@ -28,6 +28,12 @@ http { try_files $uri $uri/ /index.php?$query_string; } + location = /health { + access_log off; + default_type text/plain; + return 200 'ok'; + } + location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; @@ -43,14 +49,6 @@ http { deny all; } - location = /health { - fastcgi_pass 127.0.0.1:9000; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root/index.php; - include fastcgi_params; - fastcgi_param HTTP_PROXY ""; - } - location ^~ /horizon { add_header Content-Security-Policy "default-src 'self' http: https: data: blob 'unsafe-inline' 'unsafe-eval'" always; fastcgi_pass 127.0.0.1:9000; diff --git a/be/docker/production/redis/redis.conf b/be/docker/production/redis/redis.conf index 6008e97..e10e402 100644 --- a/be/docker/production/redis/redis.conf +++ b/be/docker/production/redis/redis.conf @@ -1,3 +1,3 @@ port 6379 bind 0.0.0.0 -requirepass sutera_redis@2025 \ No newline at end of file +requirepass mykopkb_redis@2025 \ No newline at end of file diff --git a/fe/docker/nginx.conf b/fe/docker/nginx.conf index e65b452..d8d230c 100644 --- a/fe/docker/nginx.conf +++ b/fe/docker/nginx.conf @@ -7,6 +7,12 @@ server { gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; + location = /health { + access_log off; + default_type text/plain; + return 200 'ok'; + } + location / { try_files $uri $uri/ /index.html; }