Configuration

Configure LogDeck to match your environment and security requirements.

Two ways to configure

LogDeck reads its configuration from environment variables and from a JSON config file that the Settings page writes. Environment variables win: anything pinned by the environment is shown in the UI but cannot be changed there, which is what you want when the deployment, not the admin, should have the final say.

Hosts, Coolify hosts, read-only mode, and authentication can come from either source. API tokens, alert rules, and log retention live only in the config file — set through the UI, the CLI, or (for retention) an environment override.

The data directory

Everything LogDeck persists lives in one directory — the directory of its config file, /data by default:

  • config.json — hosts, Coolify hosts, read-only mode, auth, API tokens, alert rules, and log-store settings
  • logs.db — the SQLite log store
  • alerts-history.json — recently fired alerts

Mount it as a volume. Without one, all of the above is written inside the container and destroyed the next time you recreate it — you would lose your API tokens, your alert rules, and all stored log history.

volumes:
  - logdeck-data:/data

Set CONFIG_PATH to move the config file (and with it the whole directory) somewhere else, for example CONFIG_PATH=/config/logdeck.json.

Environment Variables

Server Configuration
Configure the backend server and Docker connection
DOCKER_HOSTSOptional

Comma-separated list of Docker hosts to manage. Each entry uses name=host format and supports unix://, tcp://, and ssh:// URLs.

Default: local=unix:///var/run/docker.sock
DOCKER_HOSTS=local=unix:///var/run/docker.sock

Examples:

# Local only
DOCKER_HOSTS=local=unix:///var/run/docker.sock

# Mix of local and remote TCP
DOCKER_HOSTS=local=unix:///var/run/docker.sock,staging=tcp://192.168.1.100:2375

# SSH connection (mount your SSH keys or forward agent)
DOCKER_HOSTS=local=unix:///var/run/docker.sock,prod=ssh://deploy@prod.example.com

Host names appear in the UI and in the container list so you always know which Docker daemon you are interacting with. Hosts defined here cannot be edited or removed from the Settings page; hosts added in Settings are merged with them.

Podman is supported through its Docker-compatible API socket. When DOCKER_HOSTS is unset, LogDeck probes for a local socket in order: Docker, then rootless Podman ($XDG_RUNTIME_DIR/podman/podman.sock), then rootful Podman (/run/podman/podman.sock).

CONFIG_PATHOptional

Path to the JSON config file. Its directory also holds the log store and the alert history, so it should be on a mounted volume.

Default: /data/config.json
READONLY_MODEOptional

Set to true to block every mutating operation. See Read-Only Mode below. Default: false.

PORTNot configurable

The server always listens on :8080 inside the container. Publish it on whichever host port you like (-p 8123:8080).

Log Persistence (Optional)
Retention limits for the stored logs that power History mode

Persistence is on by default and needs no configuration. These variables override the logStore section of the config file. See Log History for the full picture.

LOG_STORE_ENABLEDOptional

false disables log persistence entirely: no database file, no History mode. Default: true.

LOG_STORE_PER_CONTAINER_MBOptional

Retention cap per container, in MB. Oldest lines are evicted first. Default: 50.

LOG_STORE_TOTAL_MBOptional

Retention cap for the whole store, in MB. Default: 1024.

LOG_STORE_ENABLED=true
LOG_STORE_PER_CONTAINER_MB=50
LOG_STORE_TOTAL_MB=1024
Proxies and CORS (Optional)
Only needed in specific deployments
TRUST_PROXY_HEADERSOptional

Set to true to trust X-Forwarded-For / X-Real-IP when identifying a client. LogDeck uses the client IP to rate limit the login endpoint. Enable this only behind a reverse proxy (Coolify, Traefik, Nginx); on a directly exposed server a client could spoof these headers to sidestep the rate limit.

CORS_ALLOWED_ORIGINSOptional

Comma-separated origins allowed to call the API from a browser. Only needed when the frontend is served from a different origin than the backend, such as a local dev server. The shipped image serves both from the same origin.

Default: http://localhost:5173,http://127.0.0.1:5173
Authentication (Optional)
Secure your LogDeck instance with JWT-based authentication

Authentication is completely optional

If these variables are not set, LogDeck runs without authentication — fine for local development or a trusted network. You can also enable it from the Settings page instead, with no environment variables at all; those credentials are stored in the config file. Setting them here pins auth so the UI cannot change it.

These three go together: set all of them, or none of them. Setting some but not all is a startup error.

JWT_SECRETRequired for auth

Secret key used to sign session tokens. Sessions last 7 days.

JWT_SECRET=your-super-secret-key-change-this-to-something-random-min-32-chars

Generate a random secret:

openssl rand -base64 32
ADMIN_USERNAMERequired for auth

Admin username for logging in.

ADMIN_USERNAME=admin
ADMIN_PASSWORDRequired for auth

A bcrypt hash of the admin password — never plain text. LogDeck validates the hash at startup and refuses to start if it is malformed.

Generate the hash:

htpasswd -bnBC 10 '' yourPassword | tr -d ':'

# ADMIN_PASSWORD=$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

htpasswd ships with apache2-utils on Debian/Ubuntu, httpd-tools on RHEL, and is preinstalled on macOS. In a compose file, escape the $ characters as $$, or keep the hash in an .env file.

ADMIN_PASSWORD_SALTLegacy

Older LogDeck deployments hashed the admin password as SHA256(password + salt). That combination — ADMIN_PASSWORD_SALT set, with ADMIN_PASSWORD holding the resulting hex digest — is still accepted, so existing setups keep working. Use bcrypt for new ones and leave this unset.

Coolify Integration (Optional)
Persist environment variable changes across Coolify redeployments

Only needed for Coolify-managed servers

If you deploy containers through Coolify, enabling this integration ensures that environment variable changes made in LogDeck are synced to Coolify and persist across redeployments. Without it, changes are lost when Coolify redeploys.

COOLIFY_CONFIGSRequired for Coolify

Per-host Coolify configuration. Each entry maps a Docker host name (from DOCKER_HOSTS) to a Coolify instance URL and API token. Generate API tokens from your Coolify dashboard under Settings → API Tokens.

# Format: hostName|apiURL|apiToken,hostName|apiURL|apiToken
# Single host
COOLIFY_CONFIGS=local|https://your-coolify-instance.com|your-api-token

# Multiple hosts with different Coolify instances
COOLIFY_CONFIGS=prod|https://coolify-prod.example.com|token-abc,staging|https://coolify-staging.example.com|token-xyz

How it works

  • LogDeck detects Coolify-managed containers automatically via Docker labels
  • When you update environment variables, changes are synced to the Coolify API
  • Sync is best-effort: if the Coolify API is unreachable, the container update still succeeds
  • Coolify-managed containers are marked with a badge in the container list

Password Hashing

When you configure authentication through the environment, ADMIN_PASSWORD must hold a bcrypt hash — never a plain-text password. LogDeck checks the hash at startup and exits with an error if it is not a valid bcrypt string.

If instead you enable authentication from the Settings page, you type the password into the form and LogDeck hashes and stores it in the config file for you. There is nothing to generate.

Generate a bcrypt hash

htpasswd -bnBC 10 '' yourPassword | tr -d ':'
# $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

htpasswd ships with apache2-utils on Debian/Ubuntu, httpd-tools on RHEL, and is preinstalled on macOS.

Important Security Notes

• A bcrypt hash contains $ characters. In a compose file, escape them as $$, or put the hash in an .env file instead.

• Treat the hash and the JWT secret like passwords — keep them out of version control.

• Use a different JWT_SECRET per deployment. Changing it invalidates every existing session.

• The legacy SHA256(password + salt) scheme is still accepted when ADMIN_PASSWORD_SALT is set, so older deployments keep working. Prefer bcrypt for new ones.

Complete Example

Here's a complete docker-compose.yml with all configuration options:

services:
  logdeck:
    image: amoabakelvin/logdeck:latest
    container_name: logdeck
    ports:
      - "8123:8080"
    volumes:
      # Docker socket for container management
      - /var/run/docker.sock:/var/run/docker.sock
      # /proc for system stats
      - /proc:/host/proc:ro
      # Config file, stored logs, and alert history — do not skip this
      - logdeck-data:/data
      # SSH keys, if you use ssh:// hosts
      # - ~/.ssh:/root/.ssh:ro
    environment:
      # Docker hosts (local + remote example)
      DOCKER_HOSTS: "local=unix:///var/run/docker.sock,prod=ssh://deploy@prod.example.com"

      # Authentication (optional - remove to run without auth,
      # or enable it from the Settings page instead)
      JWT_SECRET: "your-super-secret-key-min-32-characters-long"
      ADMIN_USERNAME: "admin"
      ADMIN_PASSWORD: "your-bcrypt-hash"   # $$ escapes the $ in a compose file

      # Log persistence (optional - on by default)
      # LOG_STORE_PER_CONTAINER_MB: "50"
      # LOG_STORE_TOTAL_MB: "1024"

      # Read-only mode (optional)
      # READONLY_MODE: "true"

      # Behind a reverse proxy (optional)
      # TRUST_PROXY_HEADERS: "true"

      # Coolify integration (optional - host names must match DOCKER_HOSTS)
      # COOLIFY_CONFIGS: "local|https://your-coolify-instance.com|your-api-token"
    restart: unless-stopped

volumes:
  logdeck-data:

The server exposes GET /api/v1/healthz if you want to wire up an external health check. The runtime image is minimal and ships no curl or wget, so a compose healthcheck has to come from outside the container.

Read-Only Mode

Read-only mode prevents LogDeck from changing anything on your containers. It is useful in production, where you want to read logs but not touch what is running. When it is on, these are blocked for everyone, session or token:

  • Starting, stopping, restarting, and removing containers
  • Compose stack start, stop, and restart
  • Environment variable and resource-limit edits
  • The web terminal (opening a shell in a container)

Reading is unaffected: logs, history, stats, events, and container details all work as usual. LogDeck's own settings and alert rules also remain editable — read-only mode is about your containers, not about LogDeck's configuration.

Toggle it from the Settings page in the UI, or pin it with an environment variable:

READONLY_MODE=true

When READONLY_MODE is set, it takes precedence and the UI toggle is disabled — useful when the environment, not the admin, should have the final say.

API Tokens

API tokens give the LogDeck CLI and external tools their own credentials, so you never have to share your admin login. They are managed entirely in the UI — no environment variables involved:

  • Create and revoke tokens under Settings → API Access
  • Tokens are prefixed ldk_ and shown in full only once, at creation
  • Only a hash is stored; a lost token cannot be recovered, only revoked and replaced
  • Requests authenticate with an Authorization: Bearer <token> header

Scopes

Each token is created with one of two scopes.

admin — full access, equivalent to a logged-in admin session.

read — read-only. Give this one to CI jobs, dashboards, and AI agents that only need to look. A read token can:

  • Read live logs, stored log history, container details, stats, and events
  • List images, volumes, networks, and hosts

A read token cannot:

  • Mutate anything — every request that is not a GET is rejected with 403, so no start/stop/restart/remove, no stack actions, no environment or resource edits, and no changes to settings or alert rules
  • Open the web terminal
  • Read a container's environment variables (they carry secrets)
  • Read the settings endpoint, which exposes host topology and the token inventory
  • Read anything under /alerts — rules, channels, and history are denied, because channel URLs and tokens (Slack/Discord webhooks, bot tokens) are secrets

Tokens only matter when authentication is enabled; on an open instance the API is reachable without them.

Docker Socket Permissions

LogDeck needs access to the Docker socket to interact with containers. Here are some important considerations:

Security Best Practices

  • Run LogDeck only on trusted networks
  • Enable authentication if exposing LogDeck to untrusted users
  • If you only need log viewing (no container management), mount the socket as read-only (:ro)
  • Use Docker's built-in authorization plugins for fine-grained access control
  • Keep LogDeck behind a reverse proxy with TLS in production

Permission Issues

If you encounter permission errors accessing the Docker socket, ensure the user running LogDeck has appropriate permissions:

# Check socket permissions
ls -l /var/run/docker.sock

# If needed, add user to docker group (Linux)
sudo usermod -aG docker $USER

Reverse Proxy Setup

For production deployments, it's recommended to run LogDeck behind a reverse proxy like Nginx or Traefik with TLS enabled.

Nginx Example

server {
    listen 443 ssl http2;
    server_name logdeck.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:8123;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
}

Traefik Example (Docker Labels)

services:
  logdeck:
    image: amoabakelvin/logdeck:latest
    container_name: logdeck
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /proc:/host/proc:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.logdeck.rule=Host(`logdeck.example.com`)"
      - "traefik.http.routers.logdeck.entrypoints=websecure"
      - "traefik.http.routers.logdeck.tls.certresolver=letsencrypt"
      - "traefik.http.services.logdeck.loadbalancer.server.port=8080"
    restart: unless-stopped