diff --git a/.env b/.env index 597e879..4820fb6 100644 --- a/.env +++ b/.env @@ -12,6 +12,7 @@ FRONTEND_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:5174,http://loca PORT=5172 BASE_PATH=/ NODE_ENV=development +ENABLE_HTTPS_SECURITY=false # Database Path - Local MaxMind databases location MAXMIND_DB_PATH=D:\\tools\\maxmind-dbs diff --git a/Overview.json b/Overview.json index 037951c..085950e 100644 --- a/Overview.json +++ b/Overview.json @@ -205,7 +205,9 @@ "**Configurable Rate Limits** - Adjust per API key type based on your needs", "**Custom API Keys** - Define multiple API keys with different access levels", "**Origin Whitelisting** - Control which domains can use frontend API keys", + "**HTTPS Security Headers** - Toggle security headers (CSP, HSTS, COOP, CORP) based on deployment type (HTTP vs HTTPS)", "**Port Configuration** - Customize backend and frontend ports", + "**Base Path Support** - Deploy under custom URL paths for reverse proxy scenarios", "**Logging Levels** - Adjust verbosity from debug to production", "**Seq Integration** - Optional structured logging to Seq server", "**Database Path** - Configurable GeoLite2 database location" diff --git a/README.md b/README.md index 9d94697..f8cbae4 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ EXTERNAL_API_KEYS=external-dev-key-1,external-dev-key-2 PORT=5172 BASE_PATH=/ NODE_ENV=development +ENABLE_HTTPS_SECURITY=false # Database Path - Point to your MaxMind databases location MAXMIND_DB_PATH=D:\tools\maxmind-dbs # Windows @@ -322,22 +323,24 @@ npm run install:all # Install all dependencies (root + backend + frontend) ### Environment Variables -| Variable | Default | Description | -| ------------------------- | ---------------------- | -------------------------------------------- | -| `PORT` | `5172` | Server port | -| `BASE_PATH` | `/` | Application base path | -| `NODE_ENV` | `development` | Environment mode (development/production) | -| `MAXMIND_DB_PATH` | `/usr/share/maxmind` | MaxMind database directory | -| `FRONTEND_API_KEY` | `frontend-default-key` | Frontend API key | -| `EXTERNAL_API_KEYS` | `external-default-key` | External API keys (comma-separated) | -| `FRONTEND_RATE_WINDOW_MS` | `60000` | Frontend rate limit window (milliseconds) | -| `FRONTEND_RATE_MAX` | `30` | Frontend rate limit max requests | -| `EXTERNAL_RATE_WINDOW_MS` | `60000` | External rate limit window (milliseconds) | -| `EXTERNAL_RATE_MAX` | `1000` | External rate limit max requests | -| `BATCH_LIMIT` | `100` | Maximum IPs per batch request | -| `DEBOUNCE_MS` | `2000` | Frontend input debounce delay (milliseconds) | -| `SEQ_URL` | - | Seq logging server URL (optional) | -| `SEQ_API_KEY` | - | Seq API key (optional) | +| Variable | Default | Description | +| -------------------------- | ---------------------- | --------------------------------------------------------------- | +| `PORT` | `5172` | Server port | +| `BASE_PATH` | `/` | Application base path | +| `NODE_ENV` | `development` | Environment mode (development/production) | +| `ENABLE_HTTPS_SECURITY` | `false` | Enable HTTPS security headers (CSP, HSTS, COOP, CORP) | +| `MAXMIND_DB_PATH` | `/usr/share/maxmind` | MaxMind database directory | +| `FRONTEND_API_KEY` | `frontend-default-key` | Frontend API key | +| `EXTERNAL_API_KEYS` | `external-default-key` | External API keys (comma-separated) | +| `FRONTEND_ALLOWED_ORIGINS` | `http://localhost:*` | Allowed CORS origins for frontend (comma-separated) | +| `FRONTEND_RATE_WINDOW_MS` | `60000` | Frontend rate limit window (milliseconds) | +| `FRONTEND_RATE_MAX` | `30` | Frontend rate limit max requests | +| `EXTERNAL_RATE_WINDOW_MS` | `60000` | External rate limit window (milliseconds) | +| `EXTERNAL_RATE_MAX` | `1000` | External rate limit max requests | +| `BATCH_LIMIT` | `100` | Maximum IPs per batch request | +| `DEBOUNCE_MS` | `2000` | Frontend input debounce delay (milliseconds) | +| `SEQ_URL` | - | Seq logging server URL (optional) | +| `SEQ_API_KEY` | - | Seq API key (optional) | ### MaxMind Database Setup @@ -365,6 +368,15 @@ Bitip implements different rate limiting for frontend and external API consumers Rate limits are fully configurable via environment variables and include standard HTTP headers in responses. +### HTTPS Security Headers + +The `ENABLE_HTTPS_SECURITY` variable controls security headers provided by Helmet: + +- **`false` (default)**: Disables CSP, HSTS, COOP, and CORP headers - required for HTTP deployments +- **`true`**: Enables all security headers - use when deploying behind HTTPS reverse proxy (nginx, Traefik, etc.) + +**Important**: If running on plain HTTP without a reverse proxy, keep this set to `false`. Browser security policies will block resources if HTTPS security headers are enabled on HTTP connections. + ## 🐳 Docker Deployment ### Production Setup diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index c69db96..b441954 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -84,6 +84,7 @@ FRONTEND_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:5174,http://loca PORT=5172 BASE_PATH=/geoip-ui NODE_ENV=development +ENABLE_HTTPS_SECURITY=false ``` **`PORT`** @@ -119,6 +120,22 @@ NODE_ENV=development - `production` - Optimized for performance, minimal logging - **Example**: `production` +**`ENABLE_HTTPS_SECURITY`** + +- **Purpose**: Enable/disable HTTPS security headers (Helmet middleware) +- **Format**: Boolean string (`true` or `false`) +- **Required**: No +- **Default**: `false` +- **Valid Values**: + - `false` - Disables CSP, HSTS, COOP, and CORP headers (required for plain HTTP) + - `true` - Enables all security headers (use when behind HTTPS reverse proxy) +- **Use Cases**: + - Set to `false` for development on HTTP + - Set to `false` for production HTTP deployments + - Set to `true` when using HTTPS with reverse proxy (nginx, Traefik, Caddy, etc.) +- **Important**: Browser security policies will block resources if HTTPS security headers are enabled on plain HTTP connections. Only enable when serving over HTTPS. +- **Example**: `false` + --- #### MaxMind Database Configuration @@ -301,6 +318,7 @@ VITE_DEBOUNCE_MS=2000 PORT=5172 BASE_PATH=/geoip-ui NODE_ENV=development + ENABLE_HTTPS_SECURITY=false MAXMIND_DB_PATH=D:\\tools\\maxmind-dbs FRONTEND_RATE_WINDOW_MS=60000 FRONTEND_RATE_MAX=30 @@ -348,6 +366,7 @@ FRONTEND_ALLOWED_ORIGINS=https://your-domain.com,https://www.your-domain.com PORT=5172 BASE_PATH=/ NODE_ENV=production +ENABLE_HTTPS_SECURITY=true MAXMIND_DB_PATH=/usr/share/maxmind FRONTEND_RATE_WINDOW_MS=60000 FRONTEND_RATE_MAX=30 diff --git a/src/backend/index.ts b/src/backend/index.ts index 3ec5ca5..240860b 100644 --- a/src/backend/index.ts +++ b/src/backend/index.ts @@ -21,10 +21,24 @@ const app = express(); // Security middleware app.use( helmet({ - contentSecurityPolicy: false, // Disable CSP to allow HTTP access - strictTransportSecurity: false, // Disable HSTS to allow HTTP access - crossOriginOpenerPolicy: false, // Disable COOP to allow HTTP access - crossOriginResourcePolicy: false, // Disable CORP to allow HTTP access + contentSecurityPolicy: config.enableHttpsSecurity + ? { + directives: { + defaultSrc: ["'self'"], + styleSrc: ["'self'", "'unsafe-inline'", 'https://unpkg.com'], + scriptSrc: ["'self'"], + imgSrc: ["'self'", 'data:', 'https:'], + connectSrc: ["'self'"], + fontSrc: ["'self'"], + objectSrc: ["'none'"], + mediaSrc: ["'self'"], + frameSrc: ["'none'"], + }, + } + : false, + strictTransportSecurity: config.enableHttpsSecurity, + crossOriginOpenerPolicy: config.enableHttpsSecurity, + crossOriginResourcePolicy: config.enableHttpsSecurity, }) ); diff --git a/src/backend/services/config.ts b/src/backend/services/config.ts index 7110bb6..50d4fdb 100644 --- a/src/backend/services/config.ts +++ b/src/backend/services/config.ts @@ -16,6 +16,7 @@ export const config: Config = { maxmindDbPath: process.env.MAXMIND_DB_PATH || '/usr/share/maxmind', seqUrl: process.env.SEQ_URL, seqApiKey: process.env.SEQ_API_KEY, + enableHttpsSecurity: process.env.ENABLE_HTTPS_SECURITY === 'true', apiKeys: { frontend: process.env.FRONTEND_API_KEY || 'frontend-default-key', external: (process.env.EXTERNAL_API_KEYS || 'external-default-key') diff --git a/src/backend/types/index.ts b/src/backend/types/index.ts index 991287e..27a6610 100644 --- a/src/backend/types/index.ts +++ b/src/backend/types/index.ts @@ -69,6 +69,7 @@ export interface Config { maxmindDbPath: string; seqUrl?: string; seqApiKey?: string; + enableHttpsSecurity: boolean; apiKeys: { frontend: string; external: string[];