Skip to content

Docker Deployment

Kolin edited this page Nov 4, 2025 · 1 revision

Docker Deployment

This guide covers deploying LogLynx using Docker and Docker Compose.


Table of Contents


Prerequisites

Install Docker

Linux (Ubuntu/Debian)

# Update package index
sudo apt update

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add user to docker group
sudo usermod -aG docker $USER

# Start Docker
sudo systemctl start docker
sudo systemctl enable docker

# Verify
docker --version

macOS

# Download Docker Desktop from:
# https://www.docker.com/products/docker-desktop

# Or using Homebrew
brew install --cask docker

# Start Docker Desktop
open /Applications/Docker.app

# Verify
docker --version

Windows

  1. Download Docker Desktop from https://www.docker.com/products/docker-desktop
  2. Run the installer
  3. Start Docker Desktop
  4. Open PowerShell and verify:
    docker --version

Install Docker Compose

Docker Compose is included with Docker Desktop (macOS/Windows). For Linux:

# Download Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# Make executable
sudo chmod +x /usr/local/bin/docker-compose

# Verify
docker-compose --version

Quick Start

The fastest way to get LogLynx running with Docker:

# Clone repository
git clone https://github.com/K0lin/loglynx.git
cd loglynx

# Build image
docker build -t loglynx:latest .

# Create directories
mkdir -p data geoip traefik/logs

# Run container
docker run -d \
  --name loglynx \
  -p 8080:8080 \
  -v $(pwd)/data:/data \
  -v $(pwd)/geoip:/app/geoip:ro \
  -v /var/log/traefik:/traefik/logs:ro \
  loglynx:latest

# Access dashboard
# Open http://localhost:8080

Docker Run

Basic Run Command

docker run -d \
  --name loglynx \
  -p 8080:8080 \
  loglynx:latest

With Volume Mounts

docker run -d \
  --name loglynx \
  -p 8080:8080 \
  -v /path/to/data:/data \
  -v /path/to/geoip:/app/geoip:ro \
  -v /var/log/traefik:/traefik/logs:ro \
  loglynx:latest

With Environment Variables

docker run -d \
  --name loglynx \
  -p 8080:8080 \
  -e DB_PATH=/data/loglynx.db \
  -e DB_RETENTION_DAYS=90 \
  -e GEOIP_ENABLED=true \
  -e TRAEFIK_LOG_PATH=/traefik/logs/access.log \
  -e LOG_LEVEL=info \
  -v /path/to/data:/data \
  -v /path/to/geoip:/app/geoip:ro \
  -v /var/log/traefik:/traefik/logs:ro \
  loglynx:latest

With Environment File

# Create env file
cat > loglynx.env <<EOF
DB_PATH=/data/loglynx.db
DB_RETENTION_DAYS=90
GEOIP_ENABLED=true
GEOIP_CITY_DB=/app/geoip/GeoLite2-City.mmdb
GEOIP_COUNTRY_DB=/app/geoip/GeoLite2-Country.mmdb
GEOIP_ASN_DB=/app/geoip/GeoLite2-ASN.mmdb
TRAEFIK_LOG_PATH=/traefik/logs/access.log
SERVER_PORT=8080
LOG_LEVEL=info
EOF

# Run with env file
docker run -d \
  --name loglynx \
  -p 8080:8080 \
  --env-file loglynx.env \
  -v /path/to/data:/data \
  -v /path/to/geoip:/app/geoip:ro \
  -v /var/log/traefik:/traefik/logs:ro \
  loglynx:latest

Manage Container

# View logs
docker logs -f loglynx

# Stop container
docker stop loglynx

# Start container
docker start loglynx

# Restart container
docker restart loglynx

# Remove container
docker rm -f loglynx

# View stats
docker stats loglynx

# Inspect container
docker inspect loglynx

# Execute command inside container
docker exec -it loglynx sh

Docker Compose

Docker Compose simplifies multi-container deployments.

Basic Compose File

Create docker-compose.yml:

version: '3.8'

services:
  loglynx:
    image: K0lin/loglynx:latest
    container_name: loglynx
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - DB_PATH=/data/loglynx.db
      - DB_RETENTION_DAYS=60
      - GEOIP_ENABLED=true
      - GEOIP_CITY_DB=/app/geoip/GeoLite2-City.mmdb
      - GEOIP_COUNTRY_DB=/app/geoip/GeoLite2-Country.mmdb
      - GEOIP_ASN_DB=/app/geoip/GeoLite2-ASN.mmdb
      - TRAEFIK_LOG_PATH=/traefik/logs/access.log
      - SERVER_PORT=8080
      - LOG_LEVEL=info
    volumes:
      - ./data:/data
      - ./geoip:/app/geoip:ro
      - /var/log/traefik:/traefik/logs:ro

Compose with Build

version: '3.8'

services:
  loglynx:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: loglynx
    restart: unless-stopped
    ports:
      - "8080:8080"
    env_file:
      - .env
    volumes:
      - ./data:/data
      - ./geoip:/app/geoip:ro
      - /var/log/traefik:/traefik/logs:ro

Compose Commands

# Start services
docker-compose up -d

# View logs
docker-compose logs -f

# Stop services
docker-compose down

# Restart services
docker-compose restart

# Build and start
docker-compose up -d --build

# View running services
docker-compose ps

# Execute command
docker-compose exec loglynx sh

Volume Mounts

LogLynx uses three main volumes:

1. Data Volume (Required)

Stores the SQLite database.

volumes:
  - ./data:/data

Permissions: Read/write Important: Back up this directory regularly

2. GeoIP Volume (Optional)

Contains MaxMind GeoIP databases.

volumes:
  - ./geoip:/app/geoip:ro

Permissions: Read-only (:ro) Files needed:

  • GeoLite2-City.mmdb
  • GeoLite2-Country.mmdb
  • GeoLite2-ASN.mmdb

3. Log Volume (Required)

Access to Traefik log files.

volumes:
  - /var/log/traefik:/traefik/logs:ro

Permissions: Read-only (:ro) Note: Path must match your Traefik log location

Named Volumes

For persistent data with Docker-managed storage:

version: '3.8'

services:
  loglynx:
    image: K0lin/loglynx:latest
    volumes:
      - loglynx-data:/data
      - ./geoip:/app/geoip:ro
      - /var/log/traefik:/traefik/logs:ro

volumes:
  loglynx-data:
    driver: local

Environment Variables

Using .env File

Create .env in the same directory as docker-compose.yml:

# Database
DB_PATH=/data/loglynx.db
DB_MAX_OPEN_CONNS=10
DB_MAX_IDLE_CONNS=3
DB_CONN_MAX_LIFE=1h
DB_RETENTION_DAYS=60
DB_CLEANUP_INTERVAL=1h
DB_CLEANUP_TIME=02:00
DB_VACUUM_ENABLED=true

# GeoIP
GEOIP_ENABLED=true
GEOIP_CITY_DB=/app/geoip/GeoLite2-City.mmdb
GEOIP_COUNTRY_DB=/app/geoip/GeoLite2-Country.mmdb
GEOIP_ASN_DB=/app/geoip/GeoLite2-ASN.mmdb
GEOIP_CACHE_SIZE=10000

# Log Sources
TRAEFIK_LOG_PATH=/traefik/logs/access.log
TRAEFIK_LOG_FORMAT=auto
LOG_AUTO_DISCOVER=true
INITIAL_IMPORT_DAYS=60
INITIAL_IMPORT_ENABLE=true

# Server
SERVER_HOST=0.0.0.0
SERVER_PORT=8080
SERVER_PRODUCTION=true

# Logging
LOG_LEVEL=info

# Performance
METRICS_INTERVAL=5s
BATCH_SIZE=1000
WORKER_POOL_SIZE=4

Reference in Compose

version: '3.8'

services:
  loglynx:
    image: loglynx:latest
    env_file:
      - .env
    volumes:
      - ./data:/data

For detailed environment variable documentation, see Environment Variables.


Building the Image

Using Dockerfile

The project includes a multi-stage Dockerfile:

# Build image
docker build -t loglynx:latest .

# Build with custom tag
docker build -t loglynx:v1.0.0 .

# Build with no cache
docker build --no-cache -t loglynx:latest .

Build Arguments

# Build for specific Go version
docker build --build-arg GO_VERSION=1.25 -t loglynx:latest .

Multi-Architecture Build

# Enable buildx
docker buildx create --use

# Build for multiple platforms
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t loglynx:latest \
  --push .

View Image

# List images
docker images | grep loglynx

# Inspect image
docker inspect loglynx:latest

# View image layers
docker history loglynx:latest

Multi-Container Setup

With Traefik (Full Stack)

version: '3.8'

services:
  traefik:
    image: traefik:v2.10
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "8081:8080"  # Traefik dashboard
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--accesslog=true"
      - "--accesslog.filepath=/var/log/traefik/access.log"
      - "--accesslog.format=json"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-logs:/var/log/traefik

  loglynx:
    image: K0lin/loglynx:latest
    container_name: loglynx
    restart: unless-stopped
    depends_on:
      - traefik
    environment:
      - TRAEFIK_LOG_PATH=/traefik/logs/access.log
      - DB_PATH=/data/loglynx.db
      - GEOIP_ENABLED=true
    volumes:
      - ./data:/data
      - ./geoip:/app/geoip:ro
      - traefik-logs:/traefik/logs:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.loglynx.rule=Host(`loglynx.example.com`)"
      - "traefik.http.routers.loglynx.entrypoints=websecure"
      - "traefik.http.services.loglynx.loadbalancer.server.port=8080"

volumes:
  traefik-logs:
    driver: local

With Sample Application

version: '3.8'

services:
  traefik:
    image: traefik:v2.10
    ports:
      - "80:80"
    command:
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--accesslog=true"
      - "--accesslog.filepath=/var/log/traefik/access.log"
      - "--accesslog.format=json"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-logs:/var/log/traefik

  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"

  loglynx:
    image: K0lin/loglynx:latest
    ports:
      - "8080:8080"
    volumes:
      - ./data:/data
      - ./geoip:/app/geoip:ro
      - traefik-logs:/traefik/logs:ro
    environment:
      - TRAEFIK_LOG_PATH=/traefik/logs/access.log

volumes:
  traefik-logs:

Traefik Integration

Traefik Labels for LogLynx

services:
  loglynx:
    image: K0lin/loglynx:latest
    labels:
      # Enable Traefik
      - "traefik.enable=true"

      # HTTP router
      - "traefik.http.routers.loglynx.rule=Host(`loglynx.example.com`)"
      - "traefik.http.routers.loglynx.entrypoints=websecure"
      - "traefik.http.routers.loglynx.tls=true"
      - "traefik.http.routers.loglynx.tls.certresolver=letsencrypt"

      # Service
      - "traefik.http.services.loglynx.loadbalancer.server.port=8080"

      # Middleware (optional)
      - "traefik.http.routers.loglynx.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$..."

Complete Example with TLS

version: '3.8'

services:
  traefik:
    image: traefik:v2.10
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
      - "--accesslog=true"
      - "--accesslog.filepath=/var/log/traefik/access.log"
      - "--accesslog.format=json"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme.json:/acme.json
      - traefik-logs:/var/log/traefik

  loglynx:
    image: K0lin/loglynx:latest
    container_name: loglynx
    restart: unless-stopped
    environment:
      - TRAEFIK_LOG_PATH=/traefik/logs/access.log
      - DB_PATH=/data/loglynx.db
    volumes:
      - ./data:/data
      - ./geoip:/app/geoip:ro
      - traefik-logs:/traefik/logs:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.loglynx.rule=Host(`loglynx.example.com`)"
      - "traefik.http.routers.loglynx.entrypoints=websecure"
      - "traefik.http.routers.loglynx.tls=true"
      - "traefik.http.routers.loglynx.tls.certresolver=letsencrypt"
      - "traefik.http.services.loglynx.loadbalancer.server.port=8080"

volumes:
  traefik-logs:

Reverse Proxy

Nginx Reverse Proxy

server {
    listen 80;
    server_name loglynx.example.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;

        # For SSE streaming
        proxy_buffering off;
        proxy_read_timeout 86400;
    }
}

Caddy Reverse Proxy

loglynx.example.com {
    reverse_proxy localhost:8080
}

Monitoring and Logs

View Container Logs

# Follow logs
docker logs -f loglynx

# Last 100 lines
docker logs --tail 100 loglynx

# Since timestamp
docker logs --since 2025-11-04T10:00:00 loglynx

# With timestamps
docker logs -t loglynx

Docker Compose Logs

# All services
docker-compose logs -f

# Specific service
docker-compose logs -f loglynx

# Last 50 lines
docker-compose logs --tail 50

Container Stats

# Real-time stats
docker stats loglynx

# All containers
docker stats

# Format output
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"

Health Checks

Add health check to Compose:

services:
  loglynx:
    image: K0lin/loglynx:latest
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Backup and Restore

Backup Database

# Stop container
docker-compose down

# Backup data directory
tar -czf loglynx-backup-$(date +%Y%m%d).tar.gz data/

# Or use docker cp
docker cp loglynx:/data/loglynx.db ./loglynx-backup.db

# Restart container
docker-compose up -d

Restore Database

# Stop container
docker-compose down

# Restore data directory
tar -xzf loglynx-backup-20251104.tar.gz

# Or use docker cp
docker cp ./loglynx-backup.db loglynx:/data/loglynx.db

# Restart container
docker-compose up -d

Automated Backups

Create backup script:

#!/bin/bash
# backup-loglynx.sh

BACKUP_DIR="/backups/loglynx"
DATE=$(date +%Y%m%d-%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Stop container (optional)
# docker-compose stop loglynx

# Backup database
docker cp loglynx:/data/loglynx.db $BACKUP_DIR/loglynx-$DATE.db

# Restart container (if stopped)
# docker-compose start loglynx

# Keep only last 7 days
find $BACKUP_DIR -name "loglynx-*.db" -mtime +7 -delete

echo "Backup completed: $BACKUP_DIR/loglynx-$DATE.db"

Schedule with cron:

# Edit crontab
crontab -e

# Add daily backup at 3 AM
0 3 * * * /path/to/backup-loglynx.sh

Troubleshooting

Container Won't Start

# Check logs
docker logs loglynx

# Inspect container
docker inspect loglynx

# Check port conflicts
sudo lsof -i :8080

# Verify volumes exist
ls -la data/ geoip/

Permission Errors

# Fix data directory permissions
sudo chown -R 1000:1000 data/

# Or use current user
sudo chown -R $(id -u):$(id -g) data/

Database Locked

# Check for multiple containers
docker ps -a | grep loglynx

# Remove duplicate containers
docker rm -f loglynx

# Reduce connection pool
# In .env:
DB_MAX_OPEN_CONNS=5

No Logs Processed

# Verify log path
docker exec loglynx ls -lh /traefik/logs/

# Check permissions
docker exec loglynx cat /traefik/logs/access.log

# Verify mount
docker inspect loglynx | grep Mounts -A 20

High Memory Usage

# Check stats
docker stats loglynx

# Limit memory
docker run -d \
  --name loglynx \
  --memory="1g" \
  --memory-swap="2g" \
  loglynx:latest

# Or in Compose:
services:
  loglynx:
    image: K0lin/loglynx:latest
    deploy:
      resources:
        limits:
          memory: 1G
        reservations:
          memory: 512M

Production Deployment

Production Compose File

version: '3.8'

services:
  loglynx:
    image: K0lin/loglynx:latest
    container_name: loglynx
    restart: always
    environment:
      - DB_PATH=/data/loglynx.db
      - DB_MAX_OPEN_CONNS=50
      - DB_MAX_IDLE_CONNS=20
      - DB_RETENTION_DAYS=90
      - DB_CLEANUP_TIME=03:00
      - DB_VACUUM_ENABLED=true
      - GEOIP_ENABLED=true
      - GEOIP_CITY_DB=/app/geoip/GeoLite2-City.mmdb
      - GEOIP_COUNTRY_DB=/app/geoip/GeoLite2-Country.mmdb
      - GEOIP_ASN_DB=/app/geoip/GeoLite2-ASN.mmdb
      - TRAEFIK_LOG_PATH=/traefik/logs/access.log
      - TRAEFIK_LOG_FORMAT=json
      - SERVER_HOST=0.0.0.0
      - SERVER_PORT=8080
      - SERVER_PRODUCTION=true
      - LOG_LEVEL=info
      - METRICS_INTERVAL=5s
      - BATCH_SIZE=2000
      - WORKER_POOL_SIZE=8
    volumes:
      - /opt/loglynx/data:/data
      - /opt/loglynx/geoip:/app/geoip:ro
      - /var/log/traefik:/traefik/logs:ro
    deploy:
      resources:
        limits:
          cpus: '4'
          memory: 4G
        reservations:
          cpus: '2'
          memory: 2G
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.loglynx.rule=Host(`loglynx.example.com`)"
      - "traefik.http.routers.loglynx.entrypoints=websecure"
      - "traefik.http.routers.loglynx.tls=true"
      - "traefik.http.routers.loglynx.tls.certresolver=letsencrypt"
      - "traefik.http.services.loglynx.loadbalancer.server.port=8080"

Security Best Practices

  1. Use read-only volumes where possible
  2. Limit container resources
  3. Enable health checks
  4. Use secrets for sensitive data
  5. Run as non-root user (already configured in Dockerfile)
  6. Enable TLS/SSL
  7. Implement authentication (via reverse proxy)

Monitoring

Set up monitoring with Prometheus and Grafana:

version: '3.8'

services:
  loglynx:
    image: K0lin/loglynx:latest
    # ... configuration ...

  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana

volumes:
  prometheus-data:
  grafana-data:

Next Steps


Last Updated: November 2025

LogLynx Wiki

Getting Started

Deployment

Reverse proxy recommended configuration

Key features

Quick Links

API Endpoints

Configuration

Deployment

Support

Clone this wiki locally