CI / Nginx config check (push) Failing after 17s
CI / Docker compose check (push) Successful in 26s
CI / Env docs check (push) Failing after 26s
CI / Frontend deps check (push) Failing after 32s
CI / Knip (push) Has been skipped
CI / Frontend a11y check (push) Has been skipped
CI / Secrets scan (push) Failing after 40s
CI / Go build (push) Successful in 40s
CI / Frontend build (push) Successful in 1m7s
CI / go mod tidy (push) Successful in 22s
CI / Svelte strict check (push) Has been skipped
CI / Frontend QC (audit) (push) Has been skipped
CI / Frontend QC (typecheck) (push) Has been skipped
CI / Frontend QC (lint) (push) Has been skipped
CI / Go vulnerabilities (push) Successful in 1m16s
CI / Go vet (push) Successful in 2m8s
CI / Staticcheck (push) Failing after 2m12s
CI / golangci-lint (push) Successful in 2m19s
CI / Security scan (gosec) (push) Failing after 2m50s
CI / Tests (prod) (push) Has been skipped
CI / Tests (dev) (push) Has been skipped
CI / Race (prod) (push) Has been skipped
CI / Race (dev) (push) Has been skipped
- secrets-scan: gitleaks module path was renamed from github.com/gitleaks/gitleaks/v8 to github.com/zricethezav/gitleaks/v8 - docker-compose-check: create backend/.env from .env.example before running docker compose config (env file required by compose.yml) - nginx: move limit_req_zone directives outside server block to http level, where nginx requires them
108 lines
3.9 KiB
Plaintext
108 lines
3.9 KiB
Plaintext
# Define cache for API responses
|
|
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=100m inactive=60m use_temp_path=off;
|
|
|
|
# Rate limiting (per IP) — must be at http level, not inside server block
|
|
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=20r/m;
|
|
limit_req_zone $binary_remote_addr zone=dav_limit:10m rate=100r/m;
|
|
|
|
server {
|
|
listen 80;
|
|
listen 443 ssl http2;
|
|
|
|
server_name _;
|
|
|
|
# TLS certs (you'll mount them into /etc/nginx/certs)
|
|
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
|
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
|
|
|
# Security headers
|
|
add_header X-Content-Type-Options nosniff;
|
|
add_header X-Frame-Options DENY;
|
|
add_header X-XSS-Protection "1; mode=block";
|
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;
|
|
|
|
# Serve static frontend
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
# Cache immutable assets aggressively
|
|
location ~ ^/_app/immutable/ {
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
|
|
# Normal frontend routes (SPA fallback)
|
|
location / {
|
|
try_files $uri /index.html;
|
|
}
|
|
|
|
# Proxy API requests to backend
|
|
location /api/ {
|
|
limit_req zone=api_limit burst=5 nodelay;
|
|
|
|
proxy_pass http://backend:8080;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
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;
|
|
|
|
# Optional lightweight caching for API responses
|
|
proxy_cache api_cache;
|
|
proxy_cache_valid 200 1m;
|
|
proxy_cache_valid any 10s;
|
|
}
|
|
|
|
# SabreDAV - CardDAV and CalDAV
|
|
location /dav/ {
|
|
limit_req zone=dav_limit burst=20 nodelay;
|
|
|
|
# Important: rewrite to remove /dav prefix for PHP processing
|
|
rewrite ^/dav/(.*)$ /server.php/$1 break;
|
|
|
|
# Pass to PHP-FPM in sabredav container
|
|
fastcgi_pass sabredav:9000;
|
|
fastcgi_index server.php;
|
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
|
|
|
include fastcgi_params;
|
|
fastcgi_param SCRIPT_FILENAME /var/www/dav/server.php;
|
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
|
fastcgi_param REQUEST_URI $request_uri;
|
|
|
|
# Required for DAV
|
|
fastcgi_param HTTPS $https if_not_empty;
|
|
fastcgi_read_timeout 300;
|
|
fastcgi_buffering off;
|
|
|
|
# Disable caching for DAV
|
|
proxy_cache off;
|
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
|
|
|
# Allow DAV methods
|
|
if ($request_method = 'OPTIONS') {
|
|
add_header 'Access-Control-Allow-Origin' '$http_origin';
|
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PROPFIND, PROPPATCH, REPORT, MKCOL, MOVE, COPY';
|
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-None-Match,If-Modified-Since,Cache-Control,Content-Type,Range,Depth,Authorization,If-Match,Destination,Overwrite,Lock-Token,Timeout';
|
|
add_header 'Access-Control-Max-Age' 1728000;
|
|
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
|
add_header 'Content-Length' 0;
|
|
return 204;
|
|
}
|
|
|
|
# Remove security headers that interfere with DAV
|
|
add_header X-Content-Type-Options "" always;
|
|
add_header X-Frame-Options "" always;
|
|
add_header X-XSS-Protection "" always;
|
|
}
|
|
|
|
# Legacy CardDAV endpoint (backward compatibility)
|
|
location /carddav/ {
|
|
return 301 $scheme://$host/dav/addressbooks$request_uri;
|
|
}
|
|
|
|
# Legacy CalDAV endpoint (backward compatibility)
|
|
location /caldav/ {
|
|
return 301 $scheme://$host/dav/calendars$request_uri;
|
|
}
|
|
} |