# 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 ``` **`PORT`** - **Purpose**: Port number on which the backend API server listens - **Format**: Integer (1-65535) - **Required**: Yes - **Default**: 3000 (if not set) - **Development**: 5172 - **Production**: Typically 3000 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:3000/api/health`) - `/geoip-ui` - Application under subpath (e.g., `http://localhost:3000/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` --- #### 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/GeoIP` - **Docker Example**: `/usr/share/GeoIP` (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/api 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**: Full URL to the backend API (including base path and `/api` suffix) - **Format**: HTTP/HTTPS URL - **Required**: Yes - **Development Example**: `http://localhost:5172/geoip-ui/api` - **Production Example**: `https://your-domain.com/geoip-ui/api` - **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 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/api 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= EXTERNAL_API_KEYS=,, FRONTEND_ALLOWED_ORIGINS=https://your-domain.com,https://www.your-domain.com PORT=3000 BASE_PATH=/ NODE_ENV=production MAXMIND_DB_PATH=/usr/share/GeoIP 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= VITE_API_URL=https://your-domain.com/api 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`