bitip/docs/CONFIGURATION.md

496 lines
15 KiB
Markdown

# Bitip GeoIP Service - Configuration Guide
This document provides detailed information about configuring the Bitip GeoIP Service using environment variables.
## Table of Contents
- [Backend Configuration](#backend-configuration)
- [Frontend Configuration](#frontend-configuration)
- [Development Setup](#development-setup)
- [Production Setup](#production-setup)
---
## Backend Configuration
The backend is configured via environment variables, typically stored in `.env` at the project root or `src/backend/.env`.
### Configuration File Locations
- **Development**: `d:\Git\Home\Bitip\.env` (project root)
- **Production**: Set via Docker environment variables or system environment
### Backend Environment Variables
#### API Keys
```env
FRONTEND_API_KEY=frontend-dev-key
EXTERNAL_API_KEYS=external-dev-key-1,external-dev-key-2
```
**`FRONTEND_API_KEY`**
- **Purpose**: API key used by the frontend application to authenticate with the backend
- **Format**: String (alphanumeric recommended)
- **Required**: Yes
- **Security**: Change this to a secure random value in production
- **Example**: `your-secure-frontend-api-key-here`
**`EXTERNAL_API_KEYS`**
- **Purpose**: Comma-separated list of API keys for external clients (non-frontend applications)
- **Format**: Comma-separated strings
- **Required**: Yes (can be empty string if no external access needed)
- **Security**: Use strong, randomly generated keys in production
- **Example**: `key1-abc123,key2-def456,key3-ghi789`
---
#### Frontend Origin Validation
```env
FRONTEND_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:5174,http://localhost:5175
```
**`FRONTEND_ALLOWED_ORIGINS`**
- **Purpose**: Comma-separated list of allowed origins (domains) that can use the frontend API key
- **Format**: Comma-separated full URLs (including protocol and port)
- **Required**: Yes
- **Default**: `http://localhost:5173` (if not set)
- **Security**:
- Provides additional protection layer beyond rate limiting
- Validates `Origin` or `Referer` header for requests using frontend API key
- Only applies to frontend API key - external keys are not origin-restricted
- **Note**: Can be bypassed from Postman/curl, but blocks browser-based abuse from other domains
- **Development Example**: `http://localhost:5173,http://localhost:5174,http://localhost:5175`
- **Production Example**: `https://your-domain.com,https://www.your-domain.com`
- **Use Cases**:
- Prevent frontend API key theft and reuse from other websites
- Block cross-site abuse while still allowing legitimate frontend access
- Works in conjunction with CORS for defense-in-depth
- **Important Notes**:
- Must include protocol (`http://` or `https://`)
- Must include port if non-standard (e.g., `http://localhost:5173`)
- Requests without `Origin` or `Referer` header will be rejected
- Multiple origins supported for staging/production environments
---
#### Server Configuration
```env
PORT=5172
BASE_PATH=/geoip-ui
NODE_ENV=development
ENABLE_HTTPS_SECURITY=false
```
**`PORT`**
- **Purpose**: Port number on which the backend API server listens
- **Format**: Integer (1-65535)
- **Required**: Yes
- **Default**: 5172 (if not set)
- **Development**: 5172
- **Production**: Typically 5172 or 8080
- **Example**: `5172`
**`BASE_PATH`**
- **Purpose**: Base URL path for all API routes and static files
- **Format**: String starting with `/` (or just `/` for root)
- **Required**: Yes
- **Default**: `/`
- **Use Cases**:
- `/` - Application at root (e.g., `http://localhost:5172/api/health`)
- `/geoip-ui` - Application under subpath (e.g., `http://localhost:5172/geoip-ui/api/health`)
- Useful for reverse proxy scenarios or hosting multiple apps on same domain
- **Example**: `/geoip-ui`
- **Note**: All API routes are prefixed with this path automatically
**`NODE_ENV`**
- **Purpose**: Node.js environment mode
- **Format**: String
- **Required**: No (defaults to 'development')
- **Valid Values**:
- `development` - Enables verbose logging, detailed errors
- `production` - Optimized for performance, minimal logging
- **Example**: `production`
**`LOG_LEVEL`**
- **Purpose**: Minimum logging level for both console and Seq output
- **Format**: String
- **Required**: No
- **Default**: `info`
- **Valid Values**:
- `debug` - All logs including debug messages (very verbose, use only for troubleshooting)
- `info` - Informational messages, warnings, and errors (recommended for development)
- `warning` - Only warnings and errors (recommended for production)
- `error` - Only error messages (minimal logging)
- **Use Cases**:
- Development: `debug` or `info` - Full visibility into application behavior
- Production: `warning` or `error` - Reduce log volume and focus on issues
- Troubleshooting: Temporarily set to `debug` to diagnose problems
- **Example**: `warning`
- **Note**: Similar to Serilog's minimum level filtering in .NET
- **Impact**: Affects both console output and Seq structured logging
**`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
```env
MAXMIND_DB_PATH=D:\\tools\\maxmind-dbs
```
**`MAXMIND_DB_PATH`**
- **Purpose**: Absolute file system path to MaxMind GeoLite2 database files
- **Format**: Absolute path (OS-specific)
- **Required**: Yes
- **Windows Example**: `D:\\tools\\maxmind-dbs` (note double backslashes)
- **Linux Example**: `/usr/share/maxmind`
- **Docker Example**: `/usr/share/maxmind` (mounted volume)
- **Expected Files**:
- `GeoLite2-City.mmdb` - City-level geolocation database
- Provided by separate GeoIP update service or manual download
- **Note**: Bitip does NOT download databases - they must be provided externally
---
#### Rate Limiting Configuration
```env
FRONTEND_RATE_WINDOW_MS=60000
FRONTEND_RATE_MAX=30
EXTERNAL_RATE_WINDOW_MS=60000
EXTERNAL_RATE_MAX=1000
```
**`FRONTEND_RATE_WINDOW_MS`**
- **Purpose**: Time window (milliseconds) for frontend API key rate limiting
- **Format**: Integer (milliseconds)
- **Required**: Yes
- **Default**: 60000 (1 minute)
- **Example**: `60000` = 1 minute window
**`FRONTEND_RATE_MAX`**
- **Purpose**: Maximum number of requests allowed from frontend API key within the time window
- **Format**: Integer
- **Required**: Yes
- **Default**: 100
- **Example**: `100` = 100 requests per minute
**`EXTERNAL_RATE_WINDOW_MS`**
- **Purpose**: Time window (milliseconds) for external API keys rate limiting
- **Format**: Integer (milliseconds)
- **Required**: Yes
- **Default**: 60000 (1 minute)
- **Example**: `60000` = 1 minute window
**`EXTERNAL_RATE_MAX`**
- **Purpose**: Maximum number of requests allowed from external API keys within the time window
- **Format**: Integer
- **Required**: Yes
- **Default**: 1000
- **Example**: `1000` = 1000 requests per minute
---
#### Batch Configuration
```env
BATCH_LIMIT=100
DEBOUNCE_MS=2000
```
**`BATCH_LIMIT`**
- **Purpose**: Maximum number of IP addresses allowed in a single batch lookup request
- **Format**: Integer
- **Required**: Yes
- **Default**: 100
- **Example**: `100`
- **Use Case**: Prevents abuse and excessive memory usage
**`DEBOUNCE_MS`**
- **Purpose**: Debounce delay (milliseconds) for frontend input - delays API calls until user stops typing
- **Format**: Integer (milliseconds)
- **Required**: Yes
- **Default**: 2000 (2 seconds)
- **Example**: `2000` = 2 seconds
- **Note**: Also configured on frontend - backend value is for reference
---
#### Seq Logging Configuration (Optional)
```env
# SEQ_URL=http://localhost:5341
# SEQ_API_KEY=your-seq-api-key
```
**`SEQ_URL`**
- **Purpose**: URL of Seq structured logging server
- **Format**: HTTP/HTTPS URL
- **Required**: No (logging works without Seq)
- **Default**: Not set (Seq logging disabled)
- **Example**: `http://localhost:5341`
- **Use Case**: Centralized structured logging and monitoring
**`SEQ_API_KEY`**
- **Purpose**: API key for authenticating with Seq server
- **Format**: String
- **Required**: No (some Seq instances don't require authentication)
- **Default**: Not set
- **Example**: `your-seq-api-key`
---
## Frontend Configuration
The frontend is configured via environment variables, typically stored in `src/frontend/.env`.
### Configuration File Location
- **Development**: `src/frontend/.env`
- **Production**: Build-time environment variables or `.env.production`
### Frontend Environment Variables
```env
VITE_API_KEY=frontend-dev-key
VITE_API_URL=http://localhost:5172/geoip-ui
VITE_DEBOUNCE_MS=2000
```
**`VITE_API_KEY`**
- **Purpose**: API key to authenticate with the backend (must match `FRONTEND_API_KEY` in backend)
- **Format**: String
- **Required**: Yes
- **Example**: `frontend-dev-key`
- **Note**: Must match backend's `FRONTEND_API_KEY` exactly
**`VITE_API_URL`**
- **Purpose**: Base URL to the backend server
- **Format**: HTTP/HTTPS URL
- **Required**: Yes
- **Development Example**: `http://localhost:5172/geoip-ui`
- **Production Example**: `https://your-domain.com/geoip-ui`
- **Note**: Must match backend's `PORT` and `BASE_PATH` configuration.
**`VITE_DEBOUNCE_MS`**
- **Purpose**: Debounce delay (milliseconds) for IP input field - delays API calls until user stops typing
- **Format**: Integer (milliseconds)
- **Required**: Yes
- **Default**: 2000 (2 seconds)
- **Example**: `2000` = 2 seconds
- **Use Case**: Reduces API calls while user is still typing
---
## Development Setup
### Quick Start
1. **Copy `.env.example` to `.env`**:
```bash
cp .env.example .env
```
2. **Edit `.env` for development**:
```env
FRONTEND_API_KEY=frontend-dev-key
EXTERNAL_API_KEYS=external-dev-key-1,external-dev-key-2
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
EXTERNAL_RATE_WINDOW_MS=60000
EXTERNAL_RATE_MAX=1000
BATCH_LIMIT=100
DEBOUNCE_MS=2000
```
3. **Edit `src/frontend/.env`**:
```env
VITE_API_KEY=frontend-dev-key
VITE_API_URL=http://localhost:5172/geoip-ui
VITE_DEBOUNCE_MS=2000
```
4. **Ensure MaxMind databases are available**:
- Databases should be provided by separate GeoIP update service
- Place `GeoLite2-City.mmdb` in the path specified by `MAXMIND_DB_PATH`
5. **Start development servers**:
```bash
npm run dev
```
### Development URLs
- **Frontend**: http://localhost:5173/
- **Backend API**: http://localhost:5172/geoip-ui/api/
- **Health Check**: http://localhost:5172/geoip-ui/api/health
---
## Production Setup
### Environment Variables
**Backend** (via Docker or system environment):
```env
FRONTEND_API_KEY=<secure-random-key>
EXTERNAL_API_KEYS=<key1>,<key2>,<key3>
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
EXTERNAL_RATE_WINDOW_MS=60000
EXTERNAL_RATE_MAX=1000
BATCH_LIMIT=100
DEBOUNCE_MS=2000
```
**Frontend** (build-time `.env.production`):
```env
VITE_API_KEY=<same-as-backend-FRONTEND_API_KEY>
VITE_API_URL=https://your-domain.com
VITE_DEBOUNCE_MS=2000
```
### Security Recommendations
1. **Generate Strong API Keys**:
```bash
# Linux/Mac
openssl rand -hex 32
# PowerShell
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
```
2. **Never Commit Real Keys**:
- Keep `.env` in `.gitignore`
- Use `.env.example` as template only
- Use secret management in production (Docker secrets, Kubernetes secrets, etc.)
3. **Configure Allowed Origins**:
- Set `FRONTEND_ALLOWED_ORIGINS` to your actual production domain(s)
- Include all variants (www, non-www, subdomains)
- Must use HTTPS in production: `https://your-domain.com`
- This provides defense-in-depth against frontend API key theft
4. **Use HTTPS in Production**:
- Set `VITE_API_URL` to HTTPS endpoint
- Configure reverse proxy (nginx, Traefik, etc.) for TLS termination
5. **Adjust Rate Limits**:
- Based on expected traffic patterns
- Monitor and adjust as needed
- Consider more aggressive limits for frontend key (e.g., 30-50 req/min)
6. **Understanding Security Model**:
- **Frontend API Key**: Semi-public, visible in browser
- Protected by: Origin validation + Rate limiting + CORS
- Can still be extracted and used from Postman/curl
- Origin validation blocks browser-based cross-site abuse
- **External API Keys**: Fully secret, never exposed to browser
- Protected by: Rate limiting only
- For trusted backend integrations
- **Best Practice**: Use aggressive rate limiting on frontend key to make abuse impractical
---
## Troubleshooting
### Backend Won't Start
- **Check `MAXMIND_DB_PATH`**: Ensure path exists and contains `GeoLite2-City.mmdb`
- **Check Port Conflicts**: Ensure `PORT` is not already in use
- **Check Environment Loading**: Verify `.env` file is at project root
### Frontend Can't Connect to Backend
- **Check `VITE_API_URL`**: Must match backend `PORT` and `BASE_PATH`
- **Check CORS**: Backend allows frontend origin by default
- **Check API Key**: `VITE_API_KEY` must match backend `FRONTEND_API_KEY`
### Authentication Errors
- **401 Unauthorized**: API key mismatch between frontend and backend
- **Verify Keys Match**: Frontend `VITE_API_KEY` === Backend `FRONTEND_API_KEY`
### Origin Validation Errors
- **403 Forbidden - "Origin header required"**: Request missing `Origin` or `Referer` header
- **Cause**: Typically happens when testing from Postman/curl with frontend API key
- **Solution**: Use external API key for non-browser clients, or add `Origin` header manually in testing tools
- **403 Forbidden - "Invalid origin"**: Frontend origin not in allowed list
- **Check `FRONTEND_ALLOWED_ORIGINS`**: Ensure your frontend domain is listed
- **Protocol Mismatch**: Ensure protocol matches (`http://` vs `https://`)
- **Port Mismatch**: Include port if non-standard (e.g., `http://localhost:5173`)
- **Development**: Add all Vite dev server ports (5173, 5174, 5175, etc.)
- **Production**: Add all domain variants (www, non-www, subdomains)
### Rate Limiting Issues
- **429 Too Many Requests**: Exceeded rate limits
- **Increase Limits**: Adjust `*_RATE_MAX` values in `.env`
- **Check Time Window**: Adjust `*_RATE_WINDOW_MS` values
---
## Additional Resources
- **Main README**: `/README.md`
- **Breaking Changes**: `/docs/BREAKING-CHANGES-FIXED.md`
- **Package Updates**: `/docs/PACKAGE-UPDATES.md`
- **API Documentation**: See inline code comments in `/src/backend/routes/api.ts`