Version 2.0.1+ includes comprehensive security features for production deployment. This guide covers all security aspects and best practices.
Problem: Version 2.0.0 had allow_origins=["*"] which allowed ANY domain to access the API.
Solution: Configurable CORS with strict origin control.
# Development (default)
ALLOWED_ORIGINS=http://localhost:8000
# Production (multiple domains)
ALLOWED_ORIGINS=https://logs.company.com,https://logs-backup.company.comConfiguration:
- Set via
ALLOWED_ORIGINSenvironment variable - Comma-separated list of allowed domains
- No wildcards allowed
allow_credentialsdisabled for security
Protection against:
- DoS (Denial of Service) attacks
- Resource exhaustion
- API abuse
Default Limits:
RATE_LIMIT_ENABLED=true
RATE_LIMIT_UPLOAD=5/minute # Upload endpoint (strict)
RATE_LIMIT_API=30/minute # Other API endpointsCustomization:
# Stricter limits for public deployment
RATE_LIMIT_UPLOAD=2/minute
RATE_LIMIT_API=10/minute
# More relaxed for internal use
RATE_LIMIT_UPLOAD=10/minute
RATE_LIMIT_API=100/minuteResponse on limit exceeded:
{
"error": "Rate limit exceeded",
"detail": "5 per 1 minute"
}Smart authentication for external API clients while keeping the web UI accessible.
Web Frontend (Browser):
- β ALWAYS accessible - No authentication required
- Users can use the web interface without any API key
- Detected via
Refererheader (automatically sent by browsers)
API Clients (curl, scripts, external tools):
- π Requires API key when
ENABLE_AUTH=true - Protects against unauthorized programmatic access
- Detected by absence of
Refererheader
# .env file
ENABLE_AUTH=true # Enables auth for API clients (not web UI!)
API_KEY=your-super-secret-api-key-min-32-chars-recommended# Linux/Mac
openssl rand -hex 32
# Python
python -c "import secrets; print(secrets.token_urlsafe(32))"
# PowerShell
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Minimum 0 -Maximum 256 }))Web Browser (No auth needed):
Just open: http://localhost:8000
Upload files normally through the UI β
API Client (Requires auth):
# With API key - Works β
curl -X POST http://localhost:8000/api/upload \
-H "X-API-Key: your-api-key-here" \
-F "files=@nextcloud.log"
# Without API key - Fails β
curl -X POST http://localhost:8000/api/upload \
-F "files=@nextcloud.log"
# β 401 UnauthorizedWhen ENABLE_AUTH=true, these require X-API-Key header:
POST /api/upload(only for API clients, web UI exempt)GET /api/results/{id}(only for API clients, web UI exempt)GET /api/results(only for API clients, web UI exempt)DELETE /api/results/{id}(only for API clients, web UI exempt)
GET /(homepage)GET /results.html(results page)GET /health(health check)GET /api/config(configuration info)
- Web UI is ALWAYS accessible - Users never need to enter an API key
- API key is for external tools only (scripts, monitoring, integrations)
- Never commit API keys to version control (use
.envfile) - Rotate API keys regularly in production
Problem: Results stored indefinitely β disk space exhaustion
Solution: Automatic deletion of old files
Configuration:
CLEANUP_ENABLED=true
CLEANUP_DAYS=7 # Retention periodWhat gets cleaned:
- Analysis results in
results/directory - Uploaded files in
uploads/directory - Files older than
CLEANUP_DAYS
Cleanup timing:
- On application startup
- Can be manually triggered (future: scheduled task)
Disable cleanup:
CLEANUP_ENABLED=false # Keep all results foreverβ File size limits (2GB default)
MAX_FILE_SIZE_MB=2048 # Configurableβ File type validation
- Only allowed:
.log,.txt,.gz,.zip - Rejects:
.exe,.sh,.php, etc.
β ZIP path traversal protection
# Only extracts files from logs/ directory
if file_info.startswith('logs/') and not file_info.endswith('/'):
# Extract safelyβ No code execution
- Files are parsed as text/JSON only
- No
eval()orexec()calls - Isolated processing
# .env file
ALLOWED_ORIGINS=https://logs.yourcompany.com
ENABLE_AUTH=true
API_KEY=<generate-strong-key-here>
RATE_LIMIT_ENABLED=true
CLEANUP_ENABLED=true
CLEANUP_DAYS=30
MAX_FILE_SIZE_MB=1024version: '3.8'
services:
log-scanner:
build: .
ports:
- "127.0.0.1:8000:8000" # Only localhost (use reverse proxy)
environment:
- ALLOWED_ORIGINS=https://logs.company.com
- ENABLE_AUTH=true
- API_KEY=${API_KEY} # From .env file
- RATE_LIMIT_ENABLED=true
- RATE_LIMIT_UPLOAD=3/minute
- CLEANUP_ENABLED=true
- CLEANUP_DAYS=14
volumes:
- ./uploads:/app/uploads
- ./results:/app/results
- ./logs:/app/logs # Application logs
restart: unless-stopped
networks:
- internal
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 3s
retries: 3
networks:
internal:
driver: bridge# /etc/nginx/sites-available/log-analyzer
upstream log_analyzer {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name logs.company.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name logs.company.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/logs.company.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/logs.company.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Upload size limit
client_max_body_size 2G;
# Timeouts for large uploads
client_body_timeout 300s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
# Proxy to FastAPI
location / {
proxy_pass http://log_analyzer;
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;
# WebSocket support (if needed in future)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Rate limiting (nginx level - additional to app)
limit_req_zone $binary_remote_addr zone=upload_limit:10m rate=5r/m;
location /api/upload {
limit_req zone=upload_limit burst=2 nodelay;
proxy_pass http://log_analyzer;
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;
}
# Access logs
access_log /var/log/nginx/log-analyzer-access.log;
error_log /var/log/nginx/log-analyzer-error.log;
}Log files contain:
- β Usernames - Personal identifiers
- β IP addresses - Network locations
- β File paths - System structure
- β Timestamps - Activity patterns
- β Error messages - System information
-
Access Control
- Deploy in private network only
- Use VPN for remote access
- Enable API authentication
-
Data Retention
- Set appropriate
CLEANUP_DAYS(GDPR: 30 days recommended) - Regularly review stored results
- Delete unnecessary analyses
- Set appropriate
-
Network Isolation
- Use Docker internal networks
- Firewall rules (only allow necessary ports)
- No direct internet exposure
-
Audit Logging
- Monitor
app.logfor access patterns - Review failed authentication attempts
- Track uploaded files and analysis IDs
- Monitor
- Change default API key (if using authentication)
- Set ALLOWED_ORIGINS to your domain (not
*orlocalhost) - Enable RATE_LIMIT with appropriate limits
- Configure AUTO_CLEANUP retention period
- Review MAX_FILE_SIZE_MB limit
- Set up HTTPS with reverse proxy
- Configure firewall rules
- Test authentication is working
- Verify CORS only allows your domain
- Monitor logs regularly (
app.log) - Check disk usage (uploads + results directories)
- Review rate limit effectiveness
- Test cleanup is running (check old files deleted)
- Update dependencies monthly (
docker-compose pull && docker-compose up -d) - Backup critical results before cleanup
- Review access patterns for anomalies
- Document incidents and responses
- Review and rotate API keys
- Check for security updates
- Audit stored results
- Review rate limit logs
- Test backup restoration
- Update SSL certificates (if needed)
-
Immediate:
- Change
API_KEYimmediately - Review
app.logfor access patterns - Identify compromised analysis IDs
- Change
-
Investigation:
- Check nginx/Apache logs for source IPs
- Review uploaded files for malicious content
- Verify no data exfiltration occurred
-
Remediation:
- Block malicious IPs at firewall
- Delete compromised results
- Strengthen rate limits
- Enable authentication if disabled
-
Identify:
- Check logs:
Rate limit exceeded for IP: x.x.x.x - Verify if legitimate user or attack
- Check logs:
-
Adjust:
# Increase limits for legitimate use RATE_LIMIT_UPLOAD=10/minute RATE_LIMIT_API=50/minute -
Whitelist (if needed):
- Use nginx
allowdirective for trusted IPs - Or implement IP whitelist in application
- Use nginx
-
Immediate:
- Check
uploads/andresults/directories - Manual cleanup:
rm -rf uploads/* results/*
- Check
-
Fix:
# Reduce retention period CLEANUP_DAYS=3 # Or reduce file size limit MAX_FILE_SIZE_MB=512
-
Monitor:
- Set up disk usage alerts
- Consider external storage (S3, NFS)
- GitHub Issues: https://github.com/xXRoxXeRXx/log-scanner/issues
- Security Vulnerabilities: Report privately via GitHub Security tab
- General Support: Create discussion on GitHub
Last Updated: November 19, 2025
Version: 2.0.1+
Maintainer: xXRoxXeRXx