Skip to content

Commit 917bcdd

Browse files
committed
- trivy ignore 2.6.0 issue
- added doc about nginx config - added docker prod file for frontend
1 parent 3b374bf commit 917bcdd

File tree

5 files changed

+270
-1
lines changed

5 files changed

+270
-1
lines changed

.github/workflows/docker.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ jobs:
3131
exit-code: '1'
3232
ignore-unfixed: true
3333
severity: 'CRITICAL,HIGH'
34-
timeout: '5m0s'
34+
timeout: '5m0s'
35+
trivyignores: 'backend/.trivyignore'

backend/.trivyignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# urllib3 1.26.x CVEs - pinned due to kubernetes client incompatibility with urllib3 2.x
2+
# kubernetes==31.0.0 uses HTTPResponse.getheaders() removed in urllib3 2.0
3+
# See: https://github.com/kubernetes-client/python/issues/2280
4+
5+
# CVE-2025-66418 - Unbounded decompression chain (fixed in 2.6.0)
6+
# Mitigated: Internal service communication only, no untrusted compressed responses
7+
CVE-2025-66418
8+
9+
# CVE-2025-66471 - urllib3 vulnerability (fixed in 2.6.0)
10+
# Mitigated: Internal service communication only
11+
CVE-2025-66471
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# Nginx Configuration
2+
3+
The frontend uses Nginx as a reverse proxy and static file server. This document explains the configuration in
4+
`frontend/nginx.conf`.
5+
6+
## Architecture
7+
8+
```mermaid
9+
flowchart LR
10+
Browser --> Nginx
11+
Nginx -->|/api/*| Backend[Backend :443]
12+
Nginx -->|static files| Static[/usr/share/nginx/html]
13+
```
14+
15+
Nginx serves two purposes:
16+
17+
1. **Static file server** for the Svelte frontend build
18+
2. **Reverse proxy** for API requests to the backend
19+
20+
## Configuration Breakdown
21+
22+
### Server Block
23+
24+
```nginx
25+
server {
26+
listen 5001;
27+
server_name _;
28+
root /usr/share/nginx/html;
29+
index index.html;
30+
}
31+
```
32+
33+
| Directive | Purpose |
34+
|-----------------|--------------------------------------------------|
35+
| `listen 5001` | Internal container port (mapped via K8s Service) |
36+
| `server_name _` | Catch-all server name |
37+
| `root` | Static files from Svelte build |
38+
39+
### Compression
40+
41+
```nginx
42+
gzip on;
43+
gzip_vary on;
44+
gzip_min_length 1024;
45+
gzip_types text/plain text/css text/xml text/javascript
46+
application/javascript application/xml+rss
47+
application/json application/x-font-ttf
48+
font/opentype image/svg+xml image/x-icon;
49+
```
50+
51+
Gzip compression reduces bandwidth for text-based assets. Binary files (images, fonts) are excluded as they're already
52+
compressed.
53+
54+
### API Proxy
55+
56+
```nginx
57+
location /api/ {
58+
proxy_pass https://backend:443;
59+
proxy_ssl_verify off;
60+
proxy_set_header Host $host;
61+
proxy_set_header X-Real-IP $remote_addr;
62+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
63+
proxy_set_header X-Forwarded-Proto $scheme;
64+
proxy_pass_request_headers on;
65+
proxy_set_header Cookie $http_cookie;
66+
}
67+
```
68+
69+
| Directive | Purpose |
70+
|------------------------|--------------------------------------------------|
71+
| `proxy_pass` | Forward to backend service over HTTPS |
72+
| `proxy_ssl_verify off` | Skip certificate verification (internal traffic) |
73+
| `X-Real-IP` | Pass client IP to backend for rate limiting |
74+
| `X-Forwarded-Proto` | Preserve original protocol for redirect URLs |
75+
| `Cookie` | Forward authentication cookies |
76+
77+
### SSE (Server-Sent Events)
78+
79+
SSE endpoints require special handling to prevent buffering:
80+
81+
```nginx
82+
location ~ ^/api/v1/events/ {
83+
proxy_pass https://backend:443;
84+
proxy_ssl_verify off;
85+
86+
# SSE-specific settings
87+
proxy_set_header Connection '';
88+
proxy_http_version 1.1;
89+
proxy_buffering off;
90+
proxy_cache off;
91+
proxy_read_timeout 86400s;
92+
proxy_send_timeout 86400s;
93+
proxy_set_header X-Accel-Buffering no;
94+
}
95+
```
96+
97+
| Directive | Purpose |
98+
|-----------------------------|---------------------------------------------------|
99+
| `Connection ''` | Disable connection header for HTTP/1.1 keep-alive |
100+
| `proxy_http_version 1.1` | Required for chunked transfer encoding |
101+
| `proxy_buffering off` | Stream responses immediately |
102+
| `proxy_read_timeout 86400s` | 24-hour timeout for long-lived connections |
103+
| `X-Accel-Buffering no` | Disable upstream buffering |
104+
105+
Without these settings, SSE events would be buffered and delivered in batches instead of real-time.
106+
107+
### Static Asset Caching
108+
109+
```nginx
110+
# Immutable assets (hashed filenames)
111+
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
112+
expires 1y;
113+
add_header Cache-Control "public, immutable";
114+
}
115+
116+
# Build directory
117+
location /build/ {
118+
expires 1y;
119+
add_header Cache-Control "public, max-age=31536000, immutable";
120+
}
121+
122+
# HTML (never cache)
123+
location ~* \.html$ {
124+
expires -1;
125+
add_header Cache-Control "no-store, no-cache, must-revalidate";
126+
}
127+
```
128+
129+
Svelte build outputs hashed filenames (`app.abc123.js`), making them safe to cache indefinitely. HTML files must never
130+
be cached to ensure users get the latest asset references.
131+
132+
### Security Headers
133+
134+
```nginx
135+
location / {
136+
add_header Content-Security-Policy "...";
137+
add_header X-Frame-Options "SAMEORIGIN";
138+
add_header X-Content-Type-Options "nosniff";
139+
add_header Referrer-Policy "strict-origin-when-cross-origin";
140+
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
141+
try_files $uri $uri/ /index.html;
142+
}
143+
```
144+
145+
#### Content Security Policy
146+
147+
```nginx
148+
Content-Security-Policy "
149+
default-src 'self';
150+
script-src 'self' 'unsafe-inline';
151+
style-src 'self' 'unsafe-inline';
152+
img-src 'self' data: blob:;
153+
font-src 'self' data:;
154+
object-src 'none';
155+
base-uri 'self';
156+
form-action 'self';
157+
frame-ancestors 'none';
158+
connect-src 'self';
159+
"
160+
```
161+
162+
| Directive | Value | Purpose |
163+
|-------------------|--------------------------|-------------------------------------|
164+
| `default-src` | `'self'` | Fallback for unspecified directives |
165+
| `script-src` | `'self' 'unsafe-inline'` | Allow inline scripts (Svelte) |
166+
| `style-src` | `'self' 'unsafe-inline'` | Allow inline styles (Svelte) |
167+
| `img-src` | `'self' data: blob:` | Allow data: URLs for SVG icons |
168+
| `font-src` | `'self' data:` | Allow embedded fonts |
169+
| `object-src` | `'none'` | Block plugins (Flash, Java) |
170+
| `frame-ancestors` | `'none'` | Prevent clickjacking |
171+
| `connect-src` | `'self'` | XHR/fetch/WebSocket same-origin |
172+
173+
The `data:` source is required for the Monaco editor's inline SVG icons.
174+
175+
#### Other Security Headers
176+
177+
| Header | Value | Purpose |
178+
|--------------------------|-----------------------------------|--------------------------------|
179+
| `X-Frame-Options` | `SAMEORIGIN` | Legacy clickjacking protection |
180+
| `X-Content-Type-Options` | `nosniff` | Prevent MIME sniffing |
181+
| `Referrer-Policy` | `strict-origin-when-cross-origin` | Limit referrer leakage |
182+
| `Permissions-Policy` | Deny geolocation, mic, camera | Disable unused APIs |
183+
184+
### SPA Routing
185+
186+
```nginx
187+
try_files $uri $uri/ /index.html;
188+
```
189+
190+
This directive enables client-side routing. When a URL like `/editor` is requested directly, Nginx serves `index.html`
191+
and lets the Svelte router handle the path.
192+
193+
## Deployment
194+
195+
The nginx.conf is copied into the container during build:
196+
197+
```dockerfile
198+
# frontend/Dockerfile.prod
199+
FROM nginx:alpine
200+
COPY --from=builder /app/public /usr/share/nginx/html
201+
COPY nginx.conf /etc/nginx/conf.d/default.conf
202+
```
203+
204+
To apply changes:
205+
206+
```bash
207+
docker build --no-cache -t integr8scode-frontend:latest \
208+
-f frontend/Dockerfile.prod frontend/
209+
kubectl rollout restart deployment/frontend -n integr8scode
210+
```
211+
212+
## Troubleshooting
213+
214+
### SSE connections dropping
215+
216+
Check `proxy_read_timeout`. Default is 60s which will close idle SSE connections.
217+
218+
### CSP blocking resources
219+
220+
Check browser console for CSP violation reports. Add the blocked source to the appropriate directive.
221+
222+
### 502 Bad Gateway
223+
224+
Backend service is unreachable. Verify:
225+
226+
```bash
227+
kubectl get svc backend -n integr8scode
228+
kubectl logs -n integr8scode deployment/frontend
229+
```
230+
231+
### Assets not updating
232+
233+
Clear browser cache or add cache-busting query parameters. Verify HTML files have `no-cache` headers.

frontend/Dockerfile.prod

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Build stage
2+
FROM node:20-alpine AS builder
3+
4+
WORKDIR /app
5+
6+
COPY package*.json ./
7+
RUN npm install --ignore-scripts
8+
9+
COPY . .
10+
RUN npm run build
11+
12+
# Production stage
13+
FROM nginx:alpine
14+
15+
# Copy built static files
16+
COPY --from=builder /app/public /usr/share/nginx/html
17+
18+
# Copy nginx config
19+
COPY nginx.conf /etc/nginx/conf.d/default.conf
20+
21+
EXPOSE 5001
22+
23+
CMD ["nginx", "-g", "daemon off;"]

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ nav:
121121

122122
- Operations:
123123
- CI/CD Pipeline: operations/cicd.md
124+
- Nginx Configuration: operations/nginx-configuration.md
124125
- Tracing: operations/tracing.md
125126
- Metrics:
126127
- Context Variables: operations/metrics-contextvars.md

0 commit comments

Comments
 (0)