Configuration
December 4, 2025 ยท View on GitHub
This document describes environment variables and configuration options for Santa Tracker.
๐ Environment Variables
Required Variables
ADMIN_PASSWORD
Admin dashboard password for authentication.
export ADMIN_PASSWORD="your-secure-password"
Best Practices:
- Use 16+ characters
- Include uppercase, lowercase, numbers, symbols
- Never commit to version control
- Use different passwords per environment
- Store in password manager
Optional Variables
FLASK_ENV
Application environment mode.
export FLASK_ENV="development" # or "production"
Values:
development: Development mode with debuggingproduction: Production mode (optimized)
Default: production
FLASK_DEBUG
Enable debug mode and detailed error pages.
export FLASK_DEBUG="True" # or "False"
Features when enabled:
- Auto-reload on code changes
- Interactive debugger
- Detailed error traces
- Development tools enabled
Default: False
Warning: Never enable in production!
FLASK_RUN_PORT
Port number for Flask development server.
export FLASK_RUN_PORT="8080"
Default: 5000
SECRET_KEY
Flask session encryption key.
export SECRET_KEY="your-secret-key-here"
Best Practices:
- Generate with:
python -c "import secrets; print(secrets.token_hex(32))" - Change between environments
- Keep secure and private
- Never commit to version control
Default: Generated randomly (not persistent)
FLASK_RUN_HOST
Host address for Flask development server.
export FLASK_RUN_HOST="0.0.0.0" # Listen on all interfaces
Default: 127.0.0.1 (localhost only)
LOG_LEVEL
Application logging level. Controls the verbosity of log output.
export LOG_LEVEL="INFO" # DEBUG, INFO, WARNING, ERROR, CRITICAL
Values:
DEBUG: Detailed diagnostic informationINFO: General operational information (default)WARNING: Something unexpected but not an errorERROR: A more serious problemCRITICAL: A very serious error
Default: INFO
JSON_LOGS
Enable JSON structured logging format for production log aggregators.
export JSON_LOGS="True" # or "False"
When enabled:
- Log output is formatted as JSON objects
- Each log entry includes: timestamp, name, level, message
- Compatible with log aggregators like ELK, Splunk, CloudWatch
When disabled (default):
- Human-readable log format
- Format:
YYYY-MM-DD HH:MM:SS - module_name - LEVEL - message
Default: False
๐ฉ Feature Flags
Feature flags allow you to enable or disable specific functionality without code changes.
ADVENT_ENABLED
Controls visibility and accessibility of the advent calendar feature.
export ADVENT_ENABLED="True" # or "False"
Behavior when disabled (default):
- Advent calendar navigation links are hidden from the UI
/adventpage returns 404 Not Found- All
/api/advent/*endpoints return 404 Not Found - All
/api/admin/advent/*endpoints return 404 Not Found - Advent-related JavaScript and CSS are not loaded
Behavior when enabled:
- Full advent calendar functionality is available
- Navigation links appear in the header
- All advent API endpoints are accessible
Default: False
Use case: Keep disabled until the advent calendar feature is complete and ready for production.
๐ .env File
Creating .env File
Create a .env file in the project root:
# Flask Configuration
FLASK_ENV=development
FLASK_DEBUG=True
FLASK_RUN_PORT=5000
FLASK_RUN_HOST=127.0.0.1
# Security
SECRET_KEY=your-secret-key-here-change-in-production
ADMIN_PASSWORD=your-secure-admin-password
# Feature Flags
ADVENT_ENABLED=False # Set to True when advent calendar is ready
# Optional: Database (if using external DB)
# DATABASE_URL=postgresql://user:pass@localhost/dbname
# Optional: External APIs
# SANTA_API_KEY=your-api-key
# SANTA_API_URL=https://api.example.com
Loading .env File
The application automatically loads .env using python-dotenv:
from dotenv import load_dotenv
load_dotenv()
Security Note
IMPORTANT: Add .env to .gitignore:
# Environment variables
.env
.env.local
.env.*.local
โ๏ธ Configuration File (config.py)
Basic Configuration
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
"""Base configuration"""
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
ADMIN_PASSWORD = os.environ.get('ADMIN_PASSWORD')
# Flask
DEBUG = False
TESTING = False
# Session
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
# File paths
ROUTE_DATA_FILE = 'santa_route.txt'
STATIC_FOLDER = 'static'
TEMPLATE_FOLDER = 'templates'
class DevelopmentConfig(Config):
"""Development configuration"""
DEBUG = True
SESSION_COOKIE_SECURE = False # Allow HTTP in dev
class ProductionConfig(Config):
"""Production configuration"""
DEBUG = False
SESSION_COOKIE_SECURE = True # Require HTTPS
class TestingConfig(Config):
"""Testing configuration"""
TESTING = True
DEBUG = True
Using Configuration
from config import DevelopmentConfig, ProductionConfig
# In app.py
config_class = ProductionConfig if os.environ.get('FLASK_ENV') == 'production' else DevelopmentConfig
app.config.from_object(config_class)
๐๏ธ Data File Configuration
Route Data File
Location of Santa's route data.
Default: santa_route.txt
ROUTE_DATA_FILE = os.environ.get('ROUTE_DATA_FILE', 'santa_route.txt')
Advent Calendar Data
Location of advent calendar content.
Default: src/static/data/advent_calendar.json
ADVENT_DATA_FILE = 'src/static/data/advent_calendar.json'
Database Files
SQLite databases for geographic data.
Files:
cities.sqlite3countries.sqlite3regions.sqlite3states.sqlite3subregions.sqlite3world.sqlite3
๐ External API Configuration
Santa Tracking API (Optional)
If integrating with external Santa tracking APIs:
SANTA_API_KEY=your-api-key
SANTA_API_URL=https://api.santatracker.example.com
SANTA_API_TIMEOUT=30
# In config.py
class Config:
SANTA_API_KEY = os.environ.get('SANTA_API_KEY')
SANTA_API_URL = os.environ.get('SANTA_API_URL')
SANTA_API_TIMEOUT = int(os.environ.get('SANTA_API_TIMEOUT', 30))
๐ Production Configuration
Environment Variables for Production
# Production environment
export FLASK_ENV=production
export FLASK_DEBUG=False
# Security (use strong values!)
export SECRET_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')"
export ADMIN_PASSWORD="your-very-secure-password"
# Server
export FLASK_RUN_HOST=0.0.0.0
export FLASK_RUN_PORT=5000
# Optional: Gunicorn workers
export WEB_CONCURRENCY=4
Gunicorn Configuration
Create gunicorn_config.py:
import os
# Server socket
bind = f"0.0.0.0:{os.environ.get('PORT', '5000')}"
backlog = 2048
# Worker processes
workers = int(os.environ.get('WEB_CONCURRENCY', 4))
worker_class = 'sync'
worker_connections = 1000
timeout = 30
keepalive = 2
# Logging
accesslog = '-'
errorlog = '-'
loglevel = 'info'
# Process naming
proc_name = 'santa-tracker'
# Server mechanics
daemon = False
pidfile = None
umask = 0
user = None
group = None
tmp_upload_dir = None
Run with:
gunicorn -c gunicorn_config.py src.app:app
๐ Security Hardening
Session Security
# Secure cookies
SESSION_COOKIE_SECURE = True # HTTPS only
SESSION_COOKIE_HTTPONLY = True # No JavaScript access
SESSION_COOKIE_SAMESITE = 'Lax' # CSRF protection
# Session lifetime
PERMANENT_SESSION_LIFETIME = 3600 # 1 hour
HTTPS Configuration
For production behind reverse proxy:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(
app.wsgi_app,
x_proto=1,
x_host=1
)
Content Security Policy
Add CSP headers:
@app.after_request
def set_csp(response):
response.headers['Content-Security-Policy'] = (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline' cdn.jsdelivr.net unpkg.com; "
"style-src 'self' 'unsafe-inline' cdn.jsdelivr.net unpkg.com; "
"img-src 'self' data: https:; "
"font-src 'self' data:;"
)
return response
๐งช Testing Configuration
Test Environment
# .env.test
FLASK_ENV=testing
FLASK_DEBUG=True
TESTING=True
# Use test password
ADMIN_PASSWORD=test-password
# Test database
DATABASE_URL=sqlite:///test.db
Loading Test Config
# In tests/conftest.py
import os
os.environ['FLASK_ENV'] = 'testing'
os.environ['ADMIN_PASSWORD'] = 'test-password'
๐ Logging Configuration
Centralized Logging Module
The application uses a centralized logging configuration in src/logging_config.py:
from src.logging_config import configure_logging, get_logger
# Configure logging at application startup (optional, called automatically)
configure_logging()
# Get a module-specific logger
logger = get_logger(__name__)
# Use the logger
logger.info('Application started')
logger.debug('Debug information: %s', variable)
logger.warning('Warning message')
logger.error('Error occurred')
logger.exception('Error with traceback') # Use in except blocks
Environment-Based Configuration
Control logging via environment variables:
# Set log level
export LOG_LEVEL="DEBUG" # DEBUG, INFO, WARNING, ERROR, CRITICAL
# Enable JSON structured logs for production
export JSON_LOGS="True"
Basic Module Logging
import logging
# Get a module-specific logger
logger = logging.getLogger(__name__)
# Log messages at appropriate levels
logger.debug('Detailed diagnostic info')
logger.info('General operational info')
logger.warning('Something unexpected')
logger.error('A serious problem')
logger.critical('Application cannot continue')
Production Logging
For production with file rotation:
from logging.handlers import RotatingFileHandler
if not app.debug:
# File handler with rotation
file_handler = RotatingFileHandler(
'santa-tracker.log',
maxBytes=10240000,
backupCount=10
)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('Santa Tracker startup')
Important: No print() in Production Code
Do not use print() statements in src/ modules. The CI pipeline will fail if print statements are detected.
Use logger.info() or other appropriate log levels instead.
๐ง Example Configurations
Development Setup
# .env.development
FLASK_ENV=development
FLASK_DEBUG=True
FLASK_RUN_PORT=5000
SECRET_KEY=dev-secret-key-not-secure
ADMIN_PASSWORD=admin123
Production Setup
# .env.production
FLASK_ENV=production
FLASK_DEBUG=False
FLASK_RUN_HOST=0.0.0.0
FLASK_RUN_PORT=8080
SECRET_KEY=<generated-secure-key>
ADMIN_PASSWORD=<strong-password>
Docker Setup
# Environment in Dockerfile
ENV FLASK_ENV=production
ENV FLASK_DEBUG=False
ENV FLASK_RUN_HOST=0.0.0.0
ENV FLASK_RUN_PORT=5000
# Or use docker-compose.yml
environment:
- FLASK_ENV=production
- SECRET_KEY=${SECRET_KEY}
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
โ Configuration Checklist
Development
- Create
.envfile - Set
FLASK_ENV=development - Set
FLASK_DEBUG=True - Set
ADMIN_PASSWORD - Add
.envto.gitignore
Production
- Set
FLASK_ENV=production - Set
FLASK_DEBUG=False - Generate secure
SECRET_KEY - Set strong
ADMIN_PASSWORD - Enable HTTPS
- Configure CSP headers
- Set up logging
- Configure reverse proxy
- Set appropriate worker count
- Test all endpoints