Serve frontend as static build behind Apache with API reverse-proxied

Build the React app during provisioning and serve it on :80 directly, proxying /api and /sanctum to an internal Laravel vhost on 127.0.0.1:8001. Fixes the login page not appearing at the container's root URL, since previously only the Laravel API vhost was configured and nothing served the built frontend.
This commit is contained in:
Ghassan Yusuf 2026-08-04 12:38:47 +03:00
parent 5c699a221c
commit 7198895444

View File

@ -165,6 +165,8 @@ cd "$APP_NAME/backend"
composer install
cd ../frontend
npm install
log "Building the frontend for production"
npm run build
cd /var/www/"$APP_NAME"
cd "/var/www/$APP_NAME/backend"
@ -177,11 +179,13 @@ log "Setting file permissions"
chown -R www-data:www-data "/var/www/$APP_NAME"
chmod -R 775 storage bootstrap/cache
log "Configuring Apache virtual host"
a2enmod rewrite
log "Configuring Apache virtual hosts (frontend on :80, API proxied internally on 127.0.0.1:8001)"
a2enmod rewrite proxy proxy_http
cat > "/etc/apache2/sites-available/$APP_NAME.conf" <<EOF
<VirtualHost *:80>
cat > "/etc/apache2/sites-available/$APP_NAME-api.conf" <<EOF
Listen 127.0.0.1:8001
<VirtualHost 127.0.0.1:8001>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/$APP_NAME/backend/public
@ -190,12 +194,40 @@ cat > "/etc/apache2/sites-available/$APP_NAME.conf" <<EOF
Require all granted
</Directory>
ErrorLog \${APACHE_LOG_DIR}/$APP_NAME-api-error.log
CustomLog \${APACHE_LOG_DIR}/$APP_NAME-api-access.log combined
</VirtualHost>
EOF
cat > "/etc/apache2/sites-available/$APP_NAME.conf" <<EOF
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/$APP_NAME/frontend/dist
<Directory /var/www/$APP_NAME/frontend/dist>
AllowOverride All
Require all granted
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
ProxyPreserveHost On
ProxyPass /api http://127.0.0.1:8001/api
ProxyPassReverse /api http://127.0.0.1:8001/api
ProxyPass /sanctum http://127.0.0.1:8001/sanctum
ProxyPassReverse /sanctum http://127.0.0.1:8001/sanctum
ErrorLog \${APACHE_LOG_DIR}/$APP_NAME-error.log
CustomLog \${APACHE_LOG_DIR}/$APP_NAME-access.log combined
</VirtualHost>
EOF
a2dissite 000-default.conf || true
a2ensite "$APP_NAME-api.conf"
a2ensite "$APP_NAME.conf"
systemctl reload apache2
systemctl restart apache2
@ -325,8 +357,8 @@ SUPER_ADMIN_EMAIL=$SUPER_ADMIN_EMAIL
SUPER_ADMIN_USERNAME=$SUPER_ADMIN_USERNAME
SUPER_ADMIN_PASSWORD=$SUPER_ADMIN_PASSWORD
FRONTEND_URL=http://${IP_ADDR:-localhost}:5173
SANCTUM_STATEFUL_DOMAINS=localhost:5173,localhost,127.0.0.1
FRONTEND_URL=http://${IP_ADDR:-localhost}
SANCTUM_STATEFUL_DOMAINS=${IP_ADDR:-localhost},localhost,127.0.0.1,localhost:5173
EOF
log "Generating application key, running migrations and seeders"
@ -382,13 +414,14 @@ cat <<SUMMARY
Project: $APP_NAME
Location: /var/www/$APP_NAME (backend/, frontend/)
Database: $DB_TYPE
API URL: http://${IP_ADDR:-<container-ip>}/
Web URL: http://${IP_ADDR:-<container-ip>}/ (login page — served by Apache; API is proxied internally, nothing extra to run)
MQTT broker: mqtt://${IP_ADDR:-<container-ip>}:1883, ws://${IP_ADDR:-<container-ip>}:9001
Super Admin: $SUPER_ADMIN_USERNAME / $SUPER_ADMIN_PASSWORD
Frontend dev server: run 'cd /var/www/$APP_NAME/frontend && npm run dev -- --host' then tunnel port 5173.
Queue worker: running as systemd unit '$APP_NAME-queue' (needed for MQTT event publishing).
Active development: 'cd /var/www/$APP_NAME/frontend && npm run dev -- --host' gives hot-reload on :5173;
rerun 'npm run build' there and it's picked up at the Web URL above (no restart needed).
$( [ "$INSTALL_CODE_SERVER" = "yes" ] && echo "code-server: run 'code-server /var/www/$APP_NAME' then tunnel port 8080 over SSH" )
$( [ "$INSTALL_CLAUDE_CODE" = "yes" ] && echo "Claude Code: run 'claude' inside /var/www/$APP_NAME to start" )