From 05b787bc27e862a441d753876e1cc4722fd4b3e0 Mon Sep 17 00:00:00 2001 From: Adrian Acala Date: Fri, 28 Nov 2025 17:56:19 -0800 Subject: [PATCH 1/3] Add backend URL configuration for frontend and update nginx setup - Added BACKEND_URL environment variable to docker-compose for frontend service. - Introduced a new entrypoint script to configure nginx with the BACKEND_URL at runtime. - Created a template for nginx configuration to handle API and WebSocket requests dynamically. - Updated README with instructions for configuring reverse proxy setups. Fixes #12 --- README.md | 16 ++++++++ docker-compose.yml | 2 + frontend/Dockerfile | 13 +++++- frontend/docker-entrypoint.sh | 15 +++++++ frontend/nginx.conf.template | 75 +++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 frontend/docker-entrypoint.sh create mode 100644 frontend/nginx.conf.template diff --git a/README.md b/README.md index 1573e15..ed92bfc 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,22 @@ docker compose up -d # Access the frontend at localhost:6767 ``` +### Reverse proxy / Traefik setups + +When ExcaliDash runs behind Traefik, Nginx, or another reverse proxy, configure both containers so that API + WebSocket calls resolve correctly: + +- `FRONTEND_URL` (backend) must match the public URL that users hit (e.g. `https://excalidraw.example.com`). This controls CORS and Socket.IO origin checks. +- `BACKEND_URL` (frontend) tells the Nginx container how to reach the backend from inside Docker/Kubernetes. Override it if your reverse proxy exposes the backend under a different hostname. + +```yaml +frontend: + environment: + - BACKEND_URL=excalidash-backend.default.svc.cluster.local:8000 +backend: + environment: + - FRONTEND_URL=https://excalidraw.example.com +``` + # Development ## Clone the Repository diff --git a/docker-compose.yml b/docker-compose.yml index 5a1eaef..70ad10f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,6 +32,8 @@ services: container_name: excalidash-frontend ports: - "6767:80" + environment: + - BACKEND_URL=backend:8000 depends_on: - backend networks: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 3468da4..9042f03 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -25,12 +25,23 @@ RUN npm run build # Production stage FROM nginx:alpine -# Copy custom nginx config +# Install envsubst (gettext) so we can template nginx config at runtime +RUN apk add --no-cache gettext + +# Copy nginx config template (will be processed at runtime) +COPY frontend/nginx.conf.template /etc/nginx/nginx.conf.template +# Also copy the original as fallback COPY frontend/nginx.conf /etc/nginx/nginx.conf +# Copy entrypoint script +COPY frontend/docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh + # Copy built application from builder COPY --from=builder /app/frontend/dist /usr/share/nginx/html EXPOSE 80 +# Use custom entrypoint to process nginx config template +ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh new file mode 100644 index 0000000..67e5740 --- /dev/null +++ b/frontend/docker-entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +# Set default backend URL if not provided +export BACKEND_URL="${BACKEND_URL:-backend:8000}" + +echo "Configuring nginx with BACKEND_URL: ${BACKEND_URL}" + +# Substitute environment variables in nginx config template +# Only substitute BACKEND_URL, preserve nginx variables like $http_upgrade +envsubst '${BACKEND_URL}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf + +# Execute the main command (nginx) +exec "$@" + diff --git a/frontend/nginx.conf.template b/frontend/nginx.conf.template new file mode 100644 index 0000000..596d19b --- /dev/null +++ b/frontend/nginx.conf.template @@ -0,0 +1,75 @@ +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + keepalive_timeout 65; + gzip on; + gzip_vary on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # Set maximum request body size to 50MB to handle large drawings with embedded images + client_max_body_size 50M; + + server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # API and WebSocket proxy to backend + # BACKEND_URL is substituted at container startup (default: backend:8000) + location /api/ { + proxy_pass http://${BACKEND_URL}/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + 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; + + # Buffer and timeout settings for large payloads + proxy_buffering on; + proxy_buffer_size 4k; + proxy_buffers 8 4k; + proxy_busy_buffers_size 8k; + client_body_buffer_size 128k; + + # Timeouts for large uploads (300 seconds) + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # WebSocket proxy for Socket.IO + location /socket.io/ { + proxy_pass http://${BACKEND_URL}/socket.io/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + 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; + } + + # Frontend routes + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + } +} + From f9986513f8a3609a8beb4d4556548e84479d140c Mon Sep 17 00:00:00 2001 From: Adrian Acala Date: Sat, 29 Nov 2025 11:29:43 -0800 Subject: [PATCH 2/3] Refactor nginx configuration and update README - Moved BACKEND_URL configuration to the frontend service in the README. - Added validation for the generated nginx configuration in the entrypoint script. - Removed fallback nginx configuration copy from the Dockerfile. - Adjusted nginx template to ensure proper header formatting. This improves the deployment process and clarifies configuration instructions. --- README.md | 6 +++--- frontend/Dockerfile | 2 -- frontend/docker-entrypoint.sh | 6 ++++-- frontend/nginx.conf.template | 5 ++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ed92bfc..e692e8f 100644 --- a/README.md +++ b/README.md @@ -122,12 +122,12 @@ When ExcaliDash runs behind Traefik, Nginx, or another reverse proxy, configure - `BACKEND_URL` (frontend) tells the Nginx container how to reach the backend from inside Docker/Kubernetes. Override it if your reverse proxy exposes the backend under a different hostname. ```yaml -frontend: - environment: - - BACKEND_URL=excalidash-backend.default.svc.cluster.local:8000 backend: environment: - FRONTEND_URL=https://excalidraw.example.com +frontend: + environment: + - BACKEND_URL=excalidash-backend.default.svc.cluster.local:8000 ``` # Development diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 9042f03..93821c2 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -30,8 +30,6 @@ RUN apk add --no-cache gettext # Copy nginx config template (will be processed at runtime) COPY frontend/nginx.conf.template /etc/nginx/nginx.conf.template -# Also copy the original as fallback -COPY frontend/nginx.conf /etc/nginx/nginx.conf # Copy entrypoint script COPY frontend/docker-entrypoint.sh /docker-entrypoint.sh diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh index 67e5740..59719a3 100644 --- a/frontend/docker-entrypoint.sh +++ b/frontend/docker-entrypoint.sh @@ -10,6 +10,8 @@ echo "Configuring nginx with BACKEND_URL: ${BACKEND_URL}" # Only substitute BACKEND_URL, preserve nginx variables like $http_upgrade envsubst '${BACKEND_URL}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf -# Execute the main command (nginx) -exec "$@" +# Validate the generated nginx configuration before starting +nginx -t -c /etc/nginx/nginx.conf +# Execute the main command (nginx) +exec "$@" \ No newline at end of file diff --git a/frontend/nginx.conf.template b/frontend/nginx.conf.template index 596d19b..281b701 100644 --- a/frontend/nginx.conf.template +++ b/frontend/nginx.conf.template @@ -27,7 +27,7 @@ http { proxy_pass http://${BACKEND_URL}/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; + proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Real-IP $remote_addr; @@ -71,5 +71,4 @@ http { add_header Cache-Control "public, immutable"; } } -} - +} \ No newline at end of file From f8830a8b0f546c95ca75bb94de716413030e17b4 Mon Sep 17 00:00:00 2001 From: Zimeng Xiong Date: Mon, 1 Dec 2025 13:27:31 -0800 Subject: [PATCH 3/3] add example in docker-compose, clarify README, add clearer validation, longer timeouts for websocket connections --- README.md | 12 ++++++++---- docker-compose.yml | 2 ++ frontend/docker-entrypoint.sh | 11 ++++++++--- frontend/nginx.conf.template | 10 +++++++--- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e692e8f..69a450b 100644 --- a/README.md +++ b/README.md @@ -114,19 +114,23 @@ docker compose up -d # Access the frontend at localhost:6767 ``` -### Reverse proxy / Traefik setups +### Reverse Proxy / Traefik Setups (Docker) -When ExcaliDash runs behind Traefik, Nginx, or another reverse proxy, configure both containers so that API + WebSocket calls resolve correctly: +When running ExcaliDash behind Traefik, Nginx, or another reverse proxy, configure both containers so that API + WebSocket calls resolve correctly: -- `FRONTEND_URL` (backend) must match the public URL that users hit (e.g. `https://excalidraw.example.com`). This controls CORS and Socket.IO origin checks. +- `FRONTEND_URL` (backend) must match the public URL that users hit (e.g. `https://excalidash.example.com`). This controls CORS and Socket.IO origin checks. - `BACKEND_URL` (frontend) tells the Nginx container how to reach the backend from inside Docker/Kubernetes. Override it if your reverse proxy exposes the backend under a different hostname. ```yaml +# docker-compose.yml example backend: environment: - - FRONTEND_URL=https://excalidraw.example.com + - FRONTEND_URL=https://excalidash.example.com frontend: environment: + # For standard Docker Compose (default) + # - BACKEND_URL=backend:8000 + # For Kubernetes, use the service DNS name: - BACKEND_URL=excalidash-backend.default.svc.cluster.local:8000 ``` diff --git a/docker-compose.yml b/docker-compose.yml index 70ad10f..2c76f10 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,6 +33,8 @@ services: ports: - "6767:80" environment: + # Backend URL for nginx proxy (host:port format, no protocol) + # Override for reverse proxy setups (e.g., excalidash-backend.svc.cluster.local:8000) - BACKEND_URL=backend:8000 depends_on: - backend diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh index 59719a3..f1ef869 100644 --- a/frontend/docker-entrypoint.sh +++ b/frontend/docker-entrypoint.sh @@ -1,7 +1,8 @@ #!/bin/sh +# Alpine-based image uses /bin/sh (busybox ash), not bash set -e -# Set default backend URL if not provided +# Set default backend URL if not provided (host:port format, no protocol) export BACKEND_URL="${BACKEND_URL:-backend:8000}" echo "Configuring nginx with BACKEND_URL: ${BACKEND_URL}" @@ -11,7 +12,11 @@ echo "Configuring nginx with BACKEND_URL: ${BACKEND_URL}" envsubst '${BACKEND_URL}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf # Validate the generated nginx configuration before starting -nginx -t -c /etc/nginx/nginx.conf +echo "Validating nginx configuration..." +if ! nginx -t -c /etc/nginx/nginx.conf; then + echo "ERROR: nginx configuration validation failed" >&2 + exit 1 +fi # Execute the main command (nginx) -exec "$@" \ No newline at end of file +exec "$@" diff --git a/frontend/nginx.conf.template b/frontend/nginx.conf.template index 281b701..91df63c 100644 --- a/frontend/nginx.conf.template +++ b/frontend/nginx.conf.template @@ -27,7 +27,7 @@ http { proxy_pass http://${BACKEND_URL}/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; + proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Real-IP $remote_addr; @@ -52,12 +52,16 @@ http { proxy_pass http://${BACKEND_URL}/socket.io/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; + proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; 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; + + # Longer timeouts for WebSocket connections + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; } # Frontend routes @@ -71,4 +75,4 @@ http { add_header Cache-Control "public, immutable"; } } -} \ No newline at end of file +}