A real-time dashboard for analyzing Traefik logs with IP geolocation, status code analysis, and service metrics. Built with React (Shadcn UI) and Node.js.
- Real-time Log Monitoring: Live updates via WebSocket.
- IP Geolocation: Track requests by country and city.
- Comprehensive Analytics:
- Request rate and response times.
- Status code distribution.
- Service and router statistics.
- Error rate monitoring.
- Modern UI: Built with Shadcn UI components.
- Containerized: Easy deployment with Docker.
- Auto-refresh: Stats update every 5 seconds.
- Log Filtering: Filter out unknown router/service names and private IPs.
- Pagination: Paginated log table for better performance.
- Configurable Backend Service Name: No more hardcoded "backend" service name.
- IPv6 Address Support: Proper handling of IPv6 addresses.
- Multiple Log Paths Support: Monitor multiple Traefik instances simultaneously.
When using Traefik with strict SNI, bot traffic accessing services by IP address results in entries with "unknown" service/router names. You can now filter these out:
- A checkbox in the log table allows hiding entries with unknown service/router names
- The filter persists across page changes and is applied server-side for better performance
Replaced infinite scroll with traditional pagination:
- Select between 50, 100, or 150 entries per page
- Navigate with page numbers, previous/next buttons
- Shows total entries and current viewing range
- Much better performance with large log files
Fixed IPv6 address truncation issue:
- Properly handles IPv6 addresses with brackets:
[2001:db8::1]:80 - Correctly extracts IPv6 addresses without truncating at colons
- Supports both IPv4 and IPv6 with or without ports
The nginx configuration is no longer hardcoded:
- Set custom backend service name via
BACKEND_SERVICE_NAMEenvironment variable - Useful when running multiple instances or custom Docker network configurations
- Frontend container automatically uses the configured service name
Monitor logs from multiple Traefik instances:
- Comma-separated list of paths in
TRAEFIK_LOG_PATH - Can mix files and directories
- Automatically discovers
.logfiles in directories - Aggregates logs from all sources in real-time
- Docker and Docker Compose
- Traefik configured with JSON logging
- Access to Traefik log files
-
Clone the repository
git clone https://github.com/hhftechnology/traefik-log-dashboard.git cd traefik-log-dashboard -
Configure log file path
Create a
.envfile from the example:cp .env.example .env
Update your
.envfile with your custom configurations:# Multiple log paths (comma-separated) TRAEFIK_LOG_PATH=/logs/traefik1/,/logs/traefik2/,/var/log/traefik.log # Custom backend service name BACKEND_SERVICE_NAME=my-backend # Container names BACKEND_CONTAINER_NAME=my-traefik-backend FRONTEND_CONTAINER_NAME=my-traefik-frontend
backend: image: ghcr.io/hhftechnology/traefik-log-dashboard-backend:latest container_name: log-dashboard-backend restart: unless-stopped volumes: - ./config/traefik/logs:/logs:ro # Mount the Traefik logs directory - ./config/maxmind:/maxmind # Mount the Traefik logs directory environment: - PORT=3001 - TRAEFIK_LOG_FILE=/logs/access.log - USE_MAXMIND=true - MAXMIND_DB_PATH=/maxmind/GeoLite2-City.mmdb - MAXMIND_FALLBACK_ONLINE=true - GOGC=50 - GOMEMLIMIT=500MiB frontend: image: ghcr.io/hhftechnology/traefik-log-dashboard-frontend:latest container_name: log-dashboard-frontend restart: unless-stopped ports: - "3000:80" depends_on: - backend deploy: resources: limits: cpus: '0.5' memory: 256M reservations: cpus: '0.1' memory: 64M-
Build and run
docker compose down docker compose build --no-cache docker compose up -d
-
Access the dashboard
Open http://localhost:3000 in your browser.
Ensure Traefik is configured to output JSON logs:
# traefik.yml accessLog: filePath: /logs/traefik.log format: json fields: defaultMode: keep headers: defaultMode: keep| Variable | Description | Default | Example |
|---|---|---|---|
TRAEFIK_LOG_PATH | Path to Traefik logs | /logs | /var/log/traefik/access.log |
PORT | Backend API port | 3001 | 3001 |
FRONTEND_PORT | Frontend port | 3000 | 8080 |
NODE_ENV | Environment | production | development |
BACKEND_SERVICE_NAME | Backend service name for Docker networking | backend | my-traefik-backend |
BACKEND_CONTAINER_NAME | Backend container name | traefik-dashboard-backend | my-traefik-backend |
FRONTEND_CONTAINER_NAME | Frontend container name | traefik-dashboard-frontend | my-traefik-frontend |
The docker-compose.yml file supports several deployment scenarios:
- Single log file:
volumes: - /path/to/traefik.log:/logs/traefik.log:ro
- Log directory:
volumes: - /path/to/log/directory:/logs:ro
- Named volume (if using Traefik in Docker):
volumes: - traefik-logs:/logs:ro
Our application now supports offline IP geolocation using MaxMind's GeoIP2 databases, providing faster and more reliable geolocation without relying on external APIs.
The MaxMind integration provides:
- Offline geolocation - No internet required for IP lookups
- Better performance - Local database queries are much faster
- Rate limit free - No API rate limits or quotas
- Privacy - IP addresses are not sent to external services
- Reliability - No dependency on external API availability
- Fallback support - Can fallback to online APIs if needed
- Sign up for a free MaxMind account: https://www.maxmind.com/en/geolite2/signup
- Go to your account page and generate a license key
- Set the license key as an environment variable:
export MAXMIND_LICENSE_KEY=your_license_key_here
# Download the GeoLite2-City database make maxmind-download # Or download the Country database (smaller, less detailed) make maxmind-download-country# Using make USE_MAXMIND=true MAXMIND_DB_PATH=maxmind/GeoLite2-City.mmdb make run # Or directly USE_MAXMIND=true MAXMIND_DB_PATH=maxmind/GeoLite2-City.mmdb ./main# Build and run with MaxMind support make docker make docker-run # Or manually docker run -p 3001:3001 \ -v /logs:/logs \ -v $(PWD)/maxmind:/maxmind \ -e USE_MAXMIND=true \ -e MAXMIND_DB_PATH=/maxmind/GeoLite2-City.mmdb \ traefik-log-dashboard-backend| Variable | Description | Default | Example |
|---|---|---|---|
USE_MAXMIND | Enable MaxMind database | false | true |
MAXMIND_DB_PATH | Path to MaxMind database file | /maxmind/GeoLite2-City.mmdb | ./maxmind/GeoLite2-City.mmdb |
MAXMIND_FALLBACK_ONLINE | Fallback to online APIs if MaxMind fails | true | false |
- Size: ~70MB
- Data: Country, region, city, coordinates, timezone
- Accuracy: City-level
- Best for: Detailed geolocation with city information
- Size: ~6MB
- Data: Country and coordinates only
- Accuracy: Country-level
- Best for: Basic geolocation, smaller memory footprint
GET /api/maxmind/configResponse:
{ "enabled": true, "databasePath": "/maxmind/GeoLite2-City.mmdb", "fallbackToOnline": true, "databaseLoaded": true, "databaseError": "" }POST /api/maxmind/reloadUseful when you've updated the database file.
POST /api/maxmind/test Content-Type: application/json { "testIP": "8.8.8.8" }Response:
{ "success": true, "testIP": "8.8.8.8", "geoData": { "country": "United States", "city": "Mountain View", "countryCode": "US", "lat": 37.4223, "lon": -122.084, "source": "maxmind" } }- Cache: Check if IP is already cached
- MaxMind: Query local MaxMind database (if enabled)
- Online APIs: Fallback to online services (if fallback enabled)
- Cache failures: Cache failed lookups to avoid repeated attempts
Each geolocation result includes a source field indicating where the data came from:
maxmind- MaxMind databaseonline_primary- Primary online API (ip-api.com)online_fallback1- Secondary online API (ipapi.co)online_fallback2- Tertiary online API (ipinfo.io)cached- Previously cached resultprivate- Private IP addressfailed- All lookup methods failed
| Method | Latency | Rate Limits | Privacy | Offline |
|---|---|---|---|---|
| MaxMind | <1ms | None | Full | Yes |
| Online APIs | 50-200ms | Yes (45/min) | Partial | No |
# Disable fallback for maximum privacy docker run -p 3001:3001 \ -v /logs:/logs \ -v /path/to/maxmind:/maxmind \ -e USE_MAXMIND=true \ -e MAXMIND_FALLBACK_ONLINE=false \ traefik-log-dashboard-backend# Use MaxMind with online fallback docker run -p 3001:3001 \ -v /logs:/logs \ -v /path/to/maxmind:/maxmind \ -e USE_MAXMIND=true \ -e MAXMIND_FALLBACK_ONLINE=true \ traefik-log-dashboard-backend# Disable MaxMind completely docker run -p 3001:3001 \ -v /logs:/logs \ -e USE_MAXMIND=false \ traefik-log-dashboard-backendMaxMind releases updated databases regularly. To update:
-
Download the latest database:
make maxmind-download
-
Reload the database (without restarting the application):
curl -X POST http://localhost:3001/api/maxmind/reload
- Check file path:
ls -la /path/to/maxmind/GeoLite2-City.mmdb - Check permissions: Database file must be readable by the application
- Check logs for specific error messages
- Ensure you're using the City database for detailed location data
- Update to the latest database version
- Some IP ranges may have limited location data
- GeoLite2-City: ~100MB RAM usage
- GeoLite2-Country: ~20MB RAM usage
- Consider using Country database for memory-constrained environments
# Test the database locally make maxmind-test # Or manually curl -X POST http://localhost:3001/api/maxmind/test \ -H "Content-Type: application/json" \ -d '{"testIP": "8.8.8.8"}'- GeoLite2 Database: Free with attribution required
- Commercial Use: Consider MaxMind's paid GeoIP2 databases for commercial applications
- Attribution: Include MaxMind attribution in your application if required
- Updates: Free databases are updated weekly, paid databases more frequently
- Database files should be stored securely and backed up
- Consider encrypting database files at rest
- Regularly update databases for security patches
- Monitor access to the database files
- In high-security environments, disable online fallback
For MaxMind-specific issues:
- MaxMind Documentation: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
- MaxMind Support: https://support.maxmind.com/
For application-specific issues:
- Check application logs
- Use the test endpoint to verify configuration
- Check the configuration endpoint for database status
βββββββββββββββββββ βββββββββββββββββββ β β β β β Frontend ββββββΆβ Backend API β β (React/Vite) β WS β (Node.js) β β β β β βββββββββββββββββββ ββββββββββ¬βββββββββ β βΌ βββββββββββββββββββ β β β Traefik Logs β β (JSON Format) β β β βββββββββββββββββββ GET /api/stats- Get aggregated statisticsGET /api/logs- Get paginated logs with filtersGET /api/services- List all servicesGET /api/routers- List all routersGET /api/geo-stats- Geographic statisticsPOST /api/set-log-file- Change log file locationWebSocket /- Real-time log streaming
- Backend:
cd backend npm install npm run dev - Frontend:
cd frontend npm install npm run dev
# Build backend cd backend docker build -t traefik-dashboard-backend . # Build frontend cd frontend docker build -t traefik-dashboard-frontend .- Edit
backend/src/logParser.jsto extract additional fields - Update
frontend/src/components/StatsCards.tsxto display new metrics
Edit frontend/src/index.css to customize colors and styling.
- The backend keeps the last 10,000 logs in memory.
- IP geolocation results are cached for 24 hours.
- Stats are calculated incrementally for efficiency.
- WebSocket connections automatically reconnect.
- Check Traefik log file path in
.env. - Ensure Traefik is outputting JSON format.
- Check container logs:
docker compose logs backend.
- Check if backend is running:
curl http://localhost:3001/health. - Ensure ports 3000 and 3001 are not in use.
- Check browser console for errors.
- The dashboard uses ip-api.com (free tier: 45 requests/minute).
- Private IPs show as "Private Network".
- Rate limits may apply for high-traffic sites.
-
Backend:
cd backend npm install npm run dev -
Frontend:
cd frontend npm install npm run dev
# Build backend cd backend docker build -t traefik-dashboard-backend . # Build frontend cd frontend docker build -t traefik-dashboard-frontend .- Edit
backend/src/logParser.jsto extract additional fields - Update
frontend/src/components/StatsCards.tsxto display new metrics
Edit frontend/src/index.css to customize colors and styling.
- The backend keeps the last 10,000 logs in memory
- IP geolocation results are cached for 24 hours
- Stats are calculated incrementally for efficiency
- WebSocket connections automatically reconnect
mkdir -p traefik-log-dashboard/{backend/src,frontend/src/{components/ui,hooks,lib},monitoring,scripts,.github/workflows} cd traefik-log-dashboardCopy each file from the artifacts to its corresponding location in the directory structure.
cp .env.example .env # Edit .env and set TRAEFIK_LOG_PATH to your log location# Using Make make build make up # Or using Docker Compose directly docker compose build docker compose up -d| Variable | Description | Default | Example |
|---|---|---|---|
TRAEFIK_LOG_PATH | Path to Traefik logs | /logs | /var/log/traefik/access.log |
PORT | Backend API port | 3001 | 3001 |
FRONTEND_PORT | Frontend port | 3000 | 8080 |
NODE_ENV | Environment | production | development |
The dashboard expects Traefik logs in JSON format. Configure Traefik:
# traefik.yml accessLog: filePath: "/path/to/access.log" format: json- Live log streaming via WebSocket
- Auto-reconnect on connection loss
- Updates every 5 seconds
- Total requests & requests/second
- Average response time
- Status code distribution
- Error rates (4xx, 5xx)
- Service & router statistics
- Geographic distribution
- Searchable log table
- Filter by service, status, router
- IP geolocation with country/city
- Response time color coding
- Request method badges
docker compose up -ddocker compose -f docker-compose.yml -f docker-compose.dev.yml updocker compose -f docker-compose.yml -f docker-compose.prod.yml up -ddocker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d# Generate 1000 sample logs node scripts/generate-sample-logs.js logs/traefik.log 1000 # Generate continuous logs node scripts/generate-sample-logs.js logs/traefik.log 0 --continuous# Check backend health curl http://localhost:3001/health # Check frontend curl http://localhost:3000-
Check log file path:
docker compose exec backend ls -la /logs -
Verify log format is JSON:
docker compose exec backend head -n 1 /logs/traefik.log -
Check backend logs:
docker compose logs backend
- Check nginx configuration in frontend container
- Ensure firewall allows WebSocket connections
- Check for proxy/load balancer WebSocket support
- Reduce
maxLogsinbackend/src/logParser.js - Add memory limits in
docker-compose.prod.yml - Enable log rotation in Traefik
- Use Traefik as reverse proxy:
labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`dashboard.example.com`)" - "traefik.http.routers.dashboard.tls=true" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"- Or use nginx with Let's Encrypt:
# Install certbot and obtain certificate certbot certonly --webroot -w /var/www/html -d dashboard.example.comAdd basic auth with Traefik:
labels: - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$..."Access monitoring tools:
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3001 (admin/admin)
# Get statistics curl http://localhost:3001/api/stats # Get logs with pagination curl http://localhost:3001/api/logs?page=1&limit=50 # Filter logs curl http://localhost:3001/api/logs?service=api-gateway&status=200 # Get services list curl http://localhost:3001/api/services # Get geographic stats curl http://localhost:3001/api/geo-statsConnect to ws://localhost:3001 and receive:
newLog- Individual log entriesstats- Updated statisticslogs- Batch of logs
For more help, create an issue on GitHub or check the logs:
docker compose logs -f --tail=100# Start ./setup.sh # First time setup docker compose up -d # Start services make up # Alternative: using Makefile # Stop docker compose down # Stop services make down # Alternative: using Makefile # Logs docker compose logs -f # View all logs docker compose logs backend # Backend logs only docker compose logs frontend # Frontend logs only # Restart docker compose restart # Restart all services make restart # Alternative: using Makefile # Update git pull # Get latest code docker compose build --no-cache # Rebuild images docker compose up -d # Restart with new images| Issue | Solution |
|---|---|
| No logs showing | Check TRAEFIK_LOG_PATH in .env |
| Can't connect | Ensure ports 3000 & 3001 are free |
| High memory | Reduce log retention in logParser.js |
| WebSocket fails | Check firewall/proxy settings |
# Test backend health curl http://localhost:3001/health # Get current stats curl http://localhost:3001/api/stats | jq . # Get recent logs curl http://localhost:3001/api/logs?limit=10 | jq .# View running containers docker compose ps # Enter backend container docker compose exec backend sh # Enter frontend container docker compose exec frontend sh # View resource usage docker stats # Clean up everything docker compose down -v --rmi all.env- Configurationdocker-compose.yml- Service definitionsbackend/src/logParser.js- Log parsing logicfrontend/src/components/Dashboard.tsx- Main UI
- Dashboard: http://localhost:3000
- Backend API: http://localhost:3001
- Health Check: http://localhost:3001/health
# Start dev mode with hot reload docker compose -f docker-compose.yml -f docker-compose.dev.yml up # Generate test logs node scripts/generate-sample-logs.js logs/traefik.log 100 # Continuous test logs node scripts/generate-sample-logs.js logs/traefik.log 0 --continuous# Start with monitoring docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d # Access # - Prometheus: http://localhost:9090 # - Grafana: http://localhost:3001 (admin/admin)Need help? Check logs first: docker compose logs -f
- Fork the repository
- Create feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open Pull Request
MIT License - feel free to use in personal and commercial projects.
- Built with React + TypeScript
- UI components from Shadcn UI
- Charts by Recharts
- IP geolocation by ip-api.com
- Icons by Lucide

