# LogDeck documentation > LogDeck is a free, open-source (GPL-3.0), self-hosted log viewer, alerting tool, and control panel for Docker and Podman containers. Every page of the docs at https://logdeck.dev, in order. The index is https://logdeck.dev/llms.txt. --- # Getting started > What LogDeck is, what it is not, and the quickest way to run a self-hosted instance with Docker Compose. LogDeck is a free, open-source (GPL-3.0), self-hosted log viewer, alerting tool, and control panel for Docker and Podman containers. It stores container logs so they survive restarts, rebuilds, and removal, alerts you when a container dies or starts logging errors, and lets you fix things from the browser, the `logdeck` CLI, or an AI agent over MCP. The server is a single Go binary with the web frontend embedded, published as the `amoabakelvin/logdeck` Docker image. With Docker Compose it runs in a few minutes. ## What LogDeck does - Streams container logs to the browser in real time, with automatic scrolling - Stores logs locally, so you can still read them after a container restarts, gets rebuilt, or is removed - Alerts you when a container dies, gets OOM-killed, or starts logging errors - Connects to many Docker or Podman daemons, over a local socket, TCP, or SSH, from one UI - Searches and filters logs by text, regex, and log level - Starts, stops, restarts, and removes containers, or whole Compose stacks at once - Shows live CPU and memory per container, with sparklines of recent history - Edits memory limits, CPU limits, and restart policies with no container downtime - Gives you a scriptable CLI that sees everything the UI sees, with JSON output for scripts and AI agents - Runs an MCP server, so an AI assistant can read your containers and, with an admin token, act on them - Works out of the box with sensible defaults, and needs no configuration - Supports optional login sessions and scoped API tokens, or runs completely open ## What LogDeck is not - It is not a deploy tool. Keep Dockge, Komodo, or plain Compose for shipping containers. LogDeck picks up after `docker compose up -d`. - It has one admin login, with no multi-user accounts or SSO. Scripts, agents, and teammates get scoped `read` or `admin` API tokens instead. - It keeps logs on the disk of the host running LogDeck, capped by the retention limits you set. - Its container health badges are Docker-only. Everything else works the same on Podman. ## Quick start The fastest way to run LogDeck is Docker Compose: ```yaml services: logdeck: image: amoabakelvin/logdeck:latest container_name: logdeck ports: - "8123:8080" volumes: - /var/run/docker.sock:/var/run/docker.sock - /proc:/host/proc:ro # Config file, stored log history, and alert history - logdeck-data:/data restart: unless-stopped volumes: logdeck-data: ``` Save this as `docker-compose.yml` and run: ```bash docker compose up -d ``` Then open [http://localhost:8123](http://localhost:8123) in your browser. > **Keep the `logdeck-data` volume.** It is where LogDeck keeps its config file, its stored log history, and its alert history. Leave it out and all three are lost the next time the container is recreated. > **LogDeck starts without a login.** Anyone who can reach port 8123 can control your containers through the Docker socket. Before other machines can reach it, turn on authentication in Settings, or publish the port on this machine only with `"127.0.0.1:8123:8080"`. ## Next steps - [Installation](https://logdeck.dev/docs/installation): Docker Compose and `docker run` setups, more hosts, updating, and troubleshooting - [Features](https://logdeck.dev/docs/features): everything LogDeck can do - [Log history](https://logdeck.dev/docs/log-history): how stored logs work, and how to tune retention - [Alerting](https://logdeck.dev/docs/alerting): alerts on container deaths, OOM kills, health checks, and log patterns - [CLI](https://logdeck.dev/docs/cli): install the `logdeck` command-line client and work from the terminal - [MCP server](https://logdeck.dev/docs/mcp): let an AI assistant read and manage your containers - [Configuration](https://logdeck.dev/docs/configuration): environment variables, authentication, API tokens, and reverse proxies ## System requirements - Docker Engine 20.10 or later, or Podman through its Docker-compatible API socket - Access to the engine socket, `/var/run/docker.sock` for Docker - A modern web browser: Chrome, Firefox, Safari, or Edge - Network access and credentials for any remote hosts, if you manage more than one ## Getting help If something doesn't work, search the [GitHub issues](https://github.com/AmoabaKelvin/logdeck/issues) for known problems and fixes, or [open a new issue](https://github.com/AmoabaKelvin/logdeck/issues/new). --- # Installation > Install the LogDeck server with Docker Compose or docker run, mount the Docker or Podman socket, and update or troubleshoot it. LogDeck runs as one container, `amoabakelvin/logdeck`, next to the containers it watches. This page covers installing it with Docker Compose or `docker run`, connecting more hosts, updating, and fixing common problems. ## Docker Compose Docker Compose is the recommended way to run LogDeck, because the whole setup lives in one file you can edit and redeploy. ### Step 1: Create docker-compose.yml Create a `docker-compose.yml` file with this content: ```yaml services: logdeck: image: amoabakelvin/logdeck:latest container_name: logdeck ports: - "8123:8080" environment: # Optional: Manage multiple Docker hosts # DOCKER_HOSTS: local=unix:///var/run/docker.sock,prod=ssh://deploy@prod.example.com # Optional: Enable authentication (or enable it later in Settings) # JWT_SECRET: your-super-secret-key-min-32-chars # ADMIN_USERNAME: admin # ADMIN_PASSWORD: your-bcrypt-hash # Optional: Coolify integration (persists env var changes across redeployments) # Host names must match DOCKER_HOSTS # COOLIFY_CONFIGS: local|https://your-coolify-instance.com|your-api-token volumes: # Mount the Docker socket for container management - /var/run/docker.sock:/var/run/docker.sock # Mount /proc for system stats (CPU, memory usage) - /proc:/host/proc:ro # Persist the config file, stored logs, and alert history - logdeck-data:/data # Mount SSH keys if you use ssh:// hosts # - ~/.ssh:/root/.ssh:ro restart: unless-stopped volumes: logdeck-data: ``` > **Do not skip the `/data` volume.** LogDeck keeps its config file (hosts, API tokens, alert rules), its [stored log history](https://logdeck.dev/docs/log-history), and its alert history in `/data`. Without a volume, all of it is written inside the container and lost the moment you recreate it, including every log line you were counting on reading back. ### Step 2: Start LogDeck ```bash docker compose up -d ``` ### Step 3: Check it is running ```bash docker compose ps ``` ### Step 4: Open the interface Open [http://localhost:8123](http://localhost:8123) in your browser. > **LogDeck starts without a login.** Anyone who can reach port 8123 can control your containers through the Docker socket. Before other machines can reach it, turn on authentication in Settings or with the [environment variables](#with-authentication), or publish the port on this machine only with `"127.0.0.1:8123:8080"`. ## Docker run To run LogDeck without Compose, use `docker run`. ### Basic deployment ```bash docker run -d \ --name logdeck \ -p 8123:8080 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /proc:/host/proc:ro \ -v logdeck-data:/data \ --restart unless-stopped \ amoabakelvin/logdeck:latest ``` ### With authentication `ADMIN_PASSWORD` takes a bcrypt hash. Generate one with `htpasswd -bnBC 10 '' yourPassword | tr -d ':'`, and see [password hashing](https://logdeck.dev/docs/configuration#password-hashing) for details. ```bash docker run -d \ --name logdeck \ -p 8123:8080 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /proc:/host/proc:ro \ -v logdeck-data:/data \ -e JWT_SECRET=your-super-secret-key-min-32-chars \ -e ADMIN_USERNAME=admin \ -e ADMIN_PASSWORD='your-bcrypt-hash' \ --restart unless-stopped \ amoabakelvin/logdeck:latest ``` ### Multiple Docker hosts To manage more than one Docker daemon, set `DOCKER_HOSTS` to comma-separated `name=host` entries. ```bash # Local Docker + remote SSH host export DOCKER_HOSTS="local=unix:///var/run/docker.sock,prod=ssh://deploy@prod.example.com" # Then start LogDeck with docker run or docker compose ``` For `ssh://` targets, mount your SSH keys, for example `~/.ssh`, or forward your SSH agent socket into the container. ## Environment variables Every variable is optional, and LogDeck runs with none of them set. The [configuration reference](https://logdeck.dev/docs/configuration) covers each one in full, along with the config file that the Settings page writes. - [`DOCKER_HOSTS`](https://logdeck.dev/docs/configuration#docker_hosts): hosts to manage, as `name=host` entries with `unix://`, `tcp://`, or `ssh://` URLs. When unset, LogDeck auto-detects a local Docker or Podman socket. - [`CONFIG_PATH`](https://logdeck.dev/docs/configuration#config_path): path to the JSON config file. Its directory also holds the log store and alert history. Default `/data/config.json`. - [`READONLY_MODE`](https://logdeck.dev/docs/configuration#readonly_mode): `true` blocks container actions, stack actions, environment and resource edits, and the web terminal. - [`LOG_STORE_ENABLED`, `LOG_STORE_PER_CONTAINER_MB`, `LOG_STORE_TOTAL_MB`](https://logdeck.dev/docs/configuration#log-persistence): log persistence is on by default, and these turn it off or change its retention caps. Defaults `true`, `50` MB, and `1024` MB. - [`JWT_SECRET`, `ADMIN_USERNAME`, `ADMIN_PASSWORD`](https://logdeck.dev/docs/configuration#authentication): pin authentication from the environment. Leave them unset to run without authentication, or to enable it from the Settings page instead. - [`COOLIFY_CONFIGS`](https://logdeck.dev/docs/configuration#coolify-integration): per-host Coolify configuration in `hostName|apiURL|apiToken` format. Host names must match those in `DOCKER_HOSTS`. ## Docker socket access > **The Docker socket gives full access to the Docker daemon.** Mounting `/var/run/docker.sock` hands LogDeck control of your Docker daemon. Only run LogDeck on trusted networks, or enable authentication to protect access. LogDeck needs write access to the Docker socket for container management, such as start, stop, and restart. If you only need to read logs, mount the socket read-only with `:ro` and turn on [read-only mode](https://logdeck.dev/docs/configuration#read-only-mode). ## Updating LogDeck ### With Docker Compose ```bash docker compose pull docker compose up -d ``` ### With docker run ```bash docker stop logdeck docker rm logdeck docker pull amoabakelvin/logdeck:latest # Then run your docker run command again ``` ## Installing the CLI The optional `logdeck` command-line client talks to your running LogDeck server, so you can read logs, check stats, and manage containers from the terminal or from scripts. ```bash curl -fsSL https://raw.githubusercontent.com/AmoabaKelvin/logdeck/main/install.sh | sh ``` It installs a single binary for macOS or Linux, on amd64 or arm64. The [CLI reference](https://logdeck.dev/docs/cli) covers connecting it to your server and every command. ## Troubleshooting ### Container won't start Check its logs: ```bash docker logs logdeck ``` ### No containers show up Check that the Docker socket is mounted: ```bash docker inspect logdeck | grep docker.sock ``` ### Port already in use If port 8123 is taken, publish a different host port in your `docker-compose.yml` or `docker run` command: ```yaml - "8124:8080" # Use port 8124 instead ``` Still stuck? [Open an issue on GitHub](https://github.com/AmoabaKelvin/logdeck/issues) with details about your setup and the error you see. --- # Features > Every LogDeck feature: live and stored container logs, alerting, stats, multi-host, Compose stack actions, a web terminal, the CLI, and MCP. This page lists everything LogDeck does, grouped by area. LogDeck is a self-hosted log viewer, alerting tool, and control panel for Docker and Podman, and each section links to its full guide where one exists. ## Real-time log streaming Container logs stream to the browser over a WebSocket as they are written. - Live log streaming with automatic updates - Auto-scroll toggle for following new lines - Configurable tail size, and pause with a count of buffered lines - Timestamps you can show or hide - Both stdout and stderr streams ## Log persistence and history LogDeck stores logs locally, so the history outlives the container that wrote it. - LogDeck tails every container on every host into a local SQLite store, enabled by default - A Live | History toggle in the log viewer searches everything stored, on the server - History survives restarts, and rebuilds that give a container a new ID, such as `docker compose up --build` - Containers that no longer exist appear under a Removed filter, with their stored logs still readable - Retention caps evict the oldest lines first, at 50 MB per container and 1024 MB in total by default - Aggregated stack logs stay live-only [Read the guide](https://logdeck.dev/docs/log-history) ## Alerting LogDeck tells you when a container dies, gets OOM-killed, fails its health check, or starts logging errors. - Event rules on container death with a non-zero exit, OOM kills, and unhealthy health checks - Log rules on a minimum level, a regex pattern, or both - Rate thresholds such as "5 matches in 60 seconds", and per-rule cooldowns that report how many matches they suppressed - Rules can target hosts, container names, or Compose projects - Notification channels: a generic JSON webhook that Slack and Discord accept unchanged, ntfy, Gotify, and Telegram - Alert history with the delivery result of every notification [Read the guide](https://logdeck.dev/docs/alerting) ## Filtering and search Search and filters narrow a log view down to the lines you need. - Full-text search with match navigation, in highlight or exclude mode - Log level filter: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, PANIC, and unclassified lines - Regex matching - Time range presets and a custom calendar range - Color-coded log levels, collapsible JSON lines, and line pinning ## Log export Download container logs for offline analysis or to archive them. - Download the filtered view as JSON or TXT - Works in both Live and History mode - Keeps timestamps and log levels - Copy single lines or a multi-line selection to the clipboard ## Container discovery LogDeck finds every container on your hosts and keeps its status current. - Status updates driven by the engine's event stream - Container details: name, image, status, and uptime - Health badges (healthy, unhealthy, starting) for containers with a healthcheck, on Docker only, see [engine support](#engine-support-and-caveats) - Host information: engine version and container count - System resource usage: CPU and memory - Grouping by Compose project ## Multi-host management One LogDeck dashboard works across many hosts and keeps every action scoped to the right daemon. - Connect local sockets, remote TCP endpoints, or SSH hosts with `DOCKER_HOSTS` - One container list, with host badges that show where each container runs - Lifecycle actions, environment variable edits, and log streaming all go to the container's own host - With no hosts configured, LogDeck auto-detects a local Docker or Podman socket ## Container management Start, stop, and inspect containers from the UI. - Start, stop, and restart containers - Remove containers, with a confirmation step - Detailed container information - Environment variables, mounted volumes, exposed ports, labels, and metadata ## Environment variable management View and change a container's environment variables from the UI. - Display all environment variables - Add, edit, and delete variables. Saving recreates the container - Bulk import from a `.env` file - Coolify integration syncs changes to Coolify, so they persist across redeployments - LogDeck detects Coolify-managed containers and labels them in the UI - Works with Docker Compose setups ## Compose stack tools Act on a whole Compose stack instead of one container at a time. - Start, stop, or restart every container in a stack from its group header - Aggregated stack logs merge all of a stack's containers into one stream, ordered by timestamp - Color-coded container badges show which container wrote each line - Works with Docker Compose and podman-compose projects ## Stats and trends Live resource usage with a short history, across all your hosts. - Live CPU and memory readings per container - Sparklines covering the last five minutes - Per-host engine stats in multi-host setups: CPUs, memory, container counts, and version - System stats for the machine running LogDeck ## Resource limits and restart policies Change container resources without recreating or restarting anything. - Edit memory limits, CPU limits, and restart policies from the container page - LogDeck applies changes live through the engine's update API, so there is no downtime - Human-friendly inputs such as `512m` and `1g`, with validation - Blocked in read-only mode ## Images, volumes, and networks See what else lives on your hosts besides containers. - Read-only listings of images, volumes, and networks - Aggregated across all configured hosts - Text filtering and per-host error reporting ## Command-line interface The `logdeck` CLI talks to the server's HTTP API and is built for scripts and AI agents. - List containers and stacks, inspect containers, read, follow, and search logs, and check stats from the terminal - `logdeck grep` searches the recent logs of every running container across all hosts - Lifecycle actions, resource limits, and Compose stack controls - `logdeck alerts` manages alert rules, notification channels, and alert history - `logdeck login` saves named contexts, kubectl-style - Table output for people, and JSON or NDJSON output (`-o json`) for machines [Read the guide](https://logdeck.dev/docs/cli) ## MCP server `logdeck mcp` lets an AI assistant query and manage your containers over the Model Context Protocol. - A stdio MCP server for Claude Desktop, Cursor, Claude Code, and other clients - Read tools for containers, logs, cross-container search, events, stats, and stored history - Action tools for lifecycle, removal, one-shot exec, environment variables, and settings - The API token decides what it can do, with no flags to configure. A read-scoped token cannot change anything, and an admin token has the same reach it has in the UI - Uses the same HTTP API as the web UI and CLI, so there is no new server and no new auth [Read the guide](https://logdeck.dev/docs/mcp) ## Web terminal Open a real shell in any running container from the browser. - Terminal access over WebSocket - Full terminal emulation with XTerm.js - 10,000 lines of scrollback - Copy to clipboard ## Scoped API tokens The CLI and other tools get their own credentials, so nobody has to share your login. - Create and revoke tokens under Settings > API Access - Tokens start with `ldk_` and are shown only once, at creation - Two scopes: `admin` for full access and `read` for read-only - A read token cannot change anything, open the web terminal, read container environment variables, read settings, or read alert rules, channels, and history - Sent as an `Authorization: Bearer` header on the HTTP API - Work alongside the JWT sessions the web UI uses [Read the guide](https://logdeck.dev/docs/configuration#api-tokens) ## Optional authentication Protect a LogDeck instance with a login, or run it open. - JWT-based login with a 7-day session token - Enable it from the Settings page, or pin it with environment variables - Environment-configured passwords are bcrypt hashes - Rate-limited login endpoint - Can be turned off entirely ## Read-only mode Read-only mode stops LogDeck from changing your containers, while you keep reading their logs. - Blocks starting, stopping, restarting, and removing containers - Blocks Compose stack actions, environment and resource edits, and the web terminal - Toggle it from the Settings page, or pin it with the `READONLY_MODE` environment variable [Read the guide](https://logdeck.dev/docs/configuration#read-only-mode) ## Interface - Dark and light mode, following your system preference, with a manual toggle - Responsive layout for desktop, tablet, and mobile - Toast notifications that confirm actions - Keyboard shortcuts, with a cheat sheet on `?` - Virtualized log lists that handle thousands of lines without slowing down ## Engine support and caveats LogDeck talks to Podman through its Docker-compatible API socket, rootless or rootful, and can mix Docker and Podman hosts in one multi-host setup. It auto-detects local sockets in this order: Docker, then rootless Podman, then rootful Podman. Health badges are Docker-only. LogDeck reads a container's health from the engine's container list. Docker includes it there, but Podman's Docker-compatible list API does not, so containers on a Podman host show no health badge even when they define a healthcheck. Everything else works the same on both engines. ## Technical details - The web frontend is embedded in the Go server binary, so there is one binary to deploy. - There is no external database. The config file, the SQLite log store, and the alert history all live in one directory, `/data` by default. Mount it as a volume and there is nothing else to manage. - LogDeck is open source under the GPL-3.0 license. Have a feature request? [Open an issue on GitHub](https://github.com/AmoabaKelvin/logdeck/issues/new). --- # Log history > How LogDeck stores container logs in SQLite so history survives restarts, rebuilds, and removal, plus retention and the history API. LogDeck stores container logs on its own disk, so you can still read them after a container restarts, gets rebuilt with a new image, or is removed entirely. By default, LogDeck tails every container on every configured host and writes those lines to a SQLite database. That store powers **History** mode in the log viewer. It is a local convenience store, not a log aggregation platform. Retention caps bound it, it lives on the machine running LogDeck, and nothing replicates it anywhere. > **Mount a volume, or history is not history.** LogDeck writes `logs.db` into the same directory as its config file, which is `/data/logs.db` with the default `CONFIG_PATH`. If `/data` is not a mounted volume, the database sits inside the container's filesystem and disappears the next time you recreate LogDeck. The same volume also holds `config.json` (hosts, API tokens, alert rules) and `alerts-history.json`. ```yaml services: logdeck: image: amoabakelvin/logdeck:latest container_name: logdeck ports: - "8123:8080" volumes: - /var/run/docker.sock:/var/run/docker.sock - /proc:/host/proc:ro # Config file, stored logs, and alert history live here - logdeck-data:/data restart: unless-stopped volumes: logdeck-data: ``` ## What survives what LogDeck keys a container's stored history by its host and its **name**, not by its engine ID. It records every engine container ID as a separate generation of that name, and queries stitch the generations back together in timestamp order. That is why history survives operations that give a container a brand-new ID: - **Restart** (`docker restart`, a crash loop, a restart policy). One continuous timeline. - **Rebuild or recreate** (`docker compose up -d --build`, an image bump, an environment-variable edit in LogDeck). The new container appends to the same timeline under the same name. - **Removal.** The lines already stored stay readable, even though the container is gone from the engine. See [Removed containers](#removed-containers). - **Restarting LogDeck itself.** On startup, LogDeck re-reads each container's engine logs from where it left off, so it backfills lines emitted while it was down instead of losing them. > **Limits worth knowing.** > > - Backfill reads the logs the _engine_ still holds. If you remove a container while LogDeck is down, the engine discards its logs with it, and whatever LogDeck had not already stored is gone for good. > - LogDeck cannot read containers whose logging driver has no read API (`awslogs`, `syslog`, `none`, and so on). It leaves them out of the store and writes the reason to the server log. > - Renaming a container starts a new timeline, because the name is the identity. ## Using History mode On a container's log page, the toolbar shows a **Live | History** toggle whenever the store is enabled. Live streams from the engine as always. History queries the database. In History mode: - **The server applies search, level filter, and time range** across everything stored for that container, not just the lines loaded in the browser. Search accepts plain text or a regex. - Results page backwards from the newest line. A **Load older** button fetches the previous page (500 lines) until you reach the start of stored history. - Timestamps, wrapping, line selection, pinning, copying, and downloading (JSON or TXT) work the same as in Live mode. - Streaming controls (Stream, Pause, tail size, auto-scroll) are hidden, since there is nothing to stream. History is available for single containers on the container log page. **Aggregated Compose stack logs are live-only.** The stack view merges live streams and has no History toggle. The quick-look log sheet on the dashboard is live-only too, so open the container's full log page for history. ### Removed containers When LogDeck holds stored logs for a container that no longer exists on any host, the dashboard's state summary grows a **Removed** chip. "All states" hides removed containers. Click the chip, or pick _Removed_ in the state filter, to list them. A removed container shows how much log data LogDeck stores for it instead of CPU and memory, and offers a single action: **View stored logs**. Its log page opens locked to History. There is no live stream, no terminal, and no environment or resources tab, because there is no container left to inspect. ## Retention and disk use Two caps bound the store. A sweep runs every minute to enforce them by evicting the **oldest lines first**: - **Per container** (default `50` MB). Applies to a logical container, meaning all generations of the same name together. A rebuilt container does not get a fresh budget. - **Total** (default `1024` MB). Applies to the whole store, across every host and container. LogDeck never vacuums the database file. SQLite reuses freed pages, so after eviction the file plateaus at its high-water mark instead of shrinking. Size `/data` for roughly the total cap plus headroom. ## Configuration Persistence is **enabled by default**. You configure it in the config file under `logStore`, and an environment variable can override every field. The environment variable wins over the file. There is no Settings page for it. ```json { "logStore": { "enabled": true, "perContainerMB": 50, "totalMB": 1024 } } ``` Each environment variable overrides the matching config-file field: - `LOG_STORE_ENABLED`: `false` turns persistence off entirely. LogDeck creates no database file, History mode disappears from the UI, and the history endpoints report the store as disabled. Existing data stays on disk untouched. Default: `true`. - `LOG_STORE_PER_CONTAINER_MB`: per-container retention cap in MB. Must be a positive integer. LogDeck ignores anything else with a warning. Default: `50`. - `LOG_STORE_TOTAL_MB`: total retention cap in MB across the whole store. Must be a positive integer. Default: `1024`. If LogDeck cannot open the database (a read-only volume, a missing mount), it logs a warning and keeps running _without_ stored logs. Persistence never blocks startup. Look for `Log persistence is ENABLED` in the server log, with the path and the caps, to confirm it came up. ## API The HTTP API exposes the store. These are read endpoints, so a `read`-scoped API token can call them. - `GET /api/v1/history/status`: whether persistence is available (`{"enabled": true}`). - `GET /api/v1/history/containers`: every logical container the store knows about, including removed ones, with their stored size. - `GET /api/v1/history/logs`: one page of stored logs. Returns `503` when persistence is disabled. `/history/logs` takes these query parameters: | Parameter | Meaning | | ----------- | -------------------------------------------- | | `container` | Container name. Required. | | `host` | Host name. | | `search` | Text to search for. | | `regex` | Boolean. Treat `search` as a regex. | | `levels` | Comma-separated levels, including `UNKNOWN`. | | `since` | Start time, RFC3339. | | `until` | End time, RFC3339. | | `limit` | Lines per page. Default `500`, max `1000`. | | `cursor` | Page cursor from a previous response. | Pages walk backwards through history. Follow the returned `nextCursor` for older lines. ```bash curl -H "Authorization: Bearer ldk_..." \ "http://localhost:8123/api/v1/history/logs?container=api&host=local&levels=ERROR,FATAL&limit=200" ``` --- # Alerting > Alert on container deaths, OOM kills, failing health checks, and log patterns, with thresholds and cooldowns, to webhooks, ntfy, Gotify, or Telegram. LogDeck alerts you when a container dies, gets OOM-killed, fails its health check, or starts logging errors. LogDeck already watches every container's events and log stream. Alert rules match on what it sees and deliver each fired alert to every enabled notification channel. Manage rules and channels under **Settings > Alerts** in the UI, or with `logdeck alerts` from the terminal. ## Rule types ### Event rules Event rules watch container lifecycle events. Three are alertable: - `die`: the container exited. Only a **non-zero exit code** fires the rule. A clean exit (code 0) is not an alert condition. When the engine event arrives without an exit code, LogDeck inspects the container to find it. - `oom`: the OOM killer killed the container. - `unhealthy`: the container's health check transitioned to unhealthy. Recoveries (healthy or starting) do not fire. An OOM kill usually emits `oom` followed right away by a `die` with code 137. For a rule that watches both, LogDeck counts that pair as one incident and alerts once. ### Log rules Log rules match lines as they stream. A rule can set a minimum level, a regex pattern, or both. When it sets both, a line must match both: - **Minimum level.** Matches any line at that level or more severe (`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`, `PANIC`). Lines LogDeck cannot classify never pass a level filter. - **Pattern.** An RE2 regular expression, tested against the parsed message and the raw line. ## Targeting You can narrow every rule by **hosts**, **container names** (exact match), and **Compose projects**. LogDeck combines the dimensions with AND, and a dimension you leave empty matches everything. A rule with no targeting at all watches every container on every host. ## Rate thresholds and cooldowns A single stray error is rarely worth a notification. Two controls decide when matches become alerts: - **Threshold and window.** Fire only after N matches within W seconds ("5 errors in 60 seconds"). The window defaults to 60 seconds. A threshold of 0 or 1 fires on every match. - **Cooldown.** The minimum time between deliveries for the same rule and container. It defaults to **300 seconds** when unset. LogDeck does not throw away matches that land during a cooldown. It counts them, and the next alert reports how many it **suppressed**. LogDeck keeps threshold and cooldown state in memory, so it resets when LogDeck restarts. ## Channels A channel is one notification destination. LogDeck delivers every fired alert to **every enabled channel**. Add channels under **Settings > Alerts**, or with `logdeck alerts channels add`. Four types are supported: - **Webhook.** POSTs the JSON payload below to a URL. Slack and Discord incoming webhooks accept this shape unchanged, and so does anything else that takes a JSON POST. - **ntfy.** POSTs the alert text as a plain-text body to a topic URL (for example `https://ntfy.sh/mytopic`), with a `Title` header. - **Gotify.** POSTs `{title, message, priority}` to `/message` using the channel's app token. - **Telegram.** Calls the Bot API `sendMessage` with the alert text, using a bot token and a chat id. The webhook payload: ```json { "source": "logdeck", "version": 1, "text": "LogDeck alert: error spike: 5 matches (level >= ERROR) within 60s (prod/api)", "content": "LogDeck alert: error spike: 5 matches (level >= ERROR) within 60s (prod/api)", "alert": { "id": "...", "ruleId": "...", "ruleName": "error spike", "type": "log", "host": "prod", "containerId": "...", "containerName": "api", "reason": "5 matches (level >= ERROR) within 60s", "sample": "level=error msg=\"upstream timeout\"", "count": 5, "suppressed": 0, "firedAt": "2026-07-14T09:31:04Z" } } ``` > **Why it works with Slack and Discord unchanged.** LogDeck sends the same human-readable summary twice, as `text` and as `content`. Slack (and Mattermost) render `text`. Discord renders `content`. So a Slack or Discord incoming-webhook URL works as-is, with no proxy or template in between. Receivers that want to parse the alert get the full alert object in the body. Each delivery has a 10-second timeout. LogDeck retries network errors and 5xx responses once after 5 seconds, and treats other statuses as permanent. The alert history records one summary result per fired alert. It succeeds only if every enabled channel accepted the alert, and otherwise names the channel that failed. Use **Test** next to a channel in Settings, or `logdeck alerts channels test `, to verify it. With no channels configured, rules still evaluate and fire. LogDeck records the alerts in history and delivers them nowhere. ## Alert history LogDeck keeps the most recent 500 fired alerts, newest first, and mirrors them to `alerts-history.json` next to the config file. History survives a restart as long as that directory is a mounted volume. Each entry records the rule, the container and host, the reason, a sample line for log rules, how many matches LogDeck suppressed, and the delivery result. Read it under **Settings > Alerts**, with `logdeck alerts history`, or from `GET /api/v1/alerts/history`. Clear it with a single action in the UI, or with `logdeck alerts history clear`. ## Managing rules from the CLI The CLI covers everything in the Alerts settings card, so you can script the same rules across deployments. ```bash # Point alerts somewhere logdeck alerts channels add --type webhook --name slack \ --endpoint https://hooks.slack.com/services/... logdeck alerts channels add --type telegram --secret "$TELEGRAM_BOT_TOKEN" --target "$CHAT_ID" logdeck alerts channels list logdeck alerts channels test # Tell me when anything gets OOM-killed logdeck alerts rules create --type event --name oom-watch --events oom # Tell me when the api container crash-loops: 3 non-zero exits in 5 minutes logdeck alerts rules create --type event --name api-crashloop \ --events die --container api --threshold 3 --window 5m # Tell me when prod starts spewing errors, at most once every 10 minutes logdeck alerts rules create --type log --name error-spike \ --min-level ERROR --host prod --threshold 5 --window 60s --cooldown 10m # Match a specific failure, wherever it happens logdeck alerts rules create --type log --name upstream-timeouts \ --pattern "upstream (timed out|timeout)" --project checkout # Inspect and manage logdeck alerts rules # list, with targets and triggers logdeck alerts rules disable # or enable / delete logdeck alerts history --limit 20 ``` `--host`, `--container`, and `--project` are repeatable and narrow the rule. `--window` and `--cooldown` accept durations (`60s`, `5m`) or bare seconds. See the [CLI reference](https://logdeck.dev/docs/cli#alerts) for every flag. ## Storage LogDeck persists alert rules and channels to `config.json` (`/data/config.json` by default) under `alerts`, alongside hosts and API tokens. It writes fired alerts to `alerts-history.json` beside it. Mount `/data` as a volume, or you lose both when you recreate the LogDeck container. There are no alert-related environment variables. You configure alerting through the UI or the CLI only. --- # CLI reference > The logdeck CLI: install it, log in with contexts and API tokens, then read, follow, and grep logs and manage containers from the terminal. `logdeck` is the command-line client for a running LogDeck server. It talks to the same HTTP API as the web interface, so the containers, logs, stats, events, and Compose stacks you see in the UI are all available from the terminal. It is fully non-interactive and built for scripting and AI agents. Every command supports machine-readable JSON output (`-o json`), errors always go to stderr, and exit codes are consistent: 0 for success, 1 for a runtime error, 2 for a usage error. ## Install Install the latest release binary (macOS and Linux, amd64/arm64): ```bash curl -fsSL https://raw.githubusercontent.com/AmoabaKelvin/logdeck/main/install.sh | sh ``` Binaries ship on [GitHub Releases](https://github.com/AmoabaKelvin/logdeck/releases) with checksums. The installer picks the right one for your OS and architecture, verifies it against the release's `checksums.txt`, and installs it to `/usr/local/bin` or `~/.local/bin`. Check your version with `logdeck --version`. Or build from source. The CLI lives in the same Go module as the server and builds to a single static binary: ```bash cd server go build ./cmd/logdeck ./logdeck --help ``` ## Connection and authentication Connect once with `logdeck login`. It verifies the connection (a health check, plus an authenticated call when you pass a token) and saves it as a named context, kubectl-style. From then on every command uses that context: ```bash logdeck login --url https://logdeck.example.com --token ldk_... --name prod logdeck status # now talks to prod ``` Contexts persist in `~/.config/logdeck/config.json` (respecting `XDG_CONFIG_HOME`). The file stores API tokens, so the CLI creates it with `0600` permissions inside a `0700` directory. It never prints a saved token, only its `ldk_` prefix. Manage contexts with: ```bash logdeck context list # name, url, token prefix, current marker logdeck context use staging # switch the current context logdeck context rm old # delete a context logdeck logout # remove the token from the current (or named) context, keeping its URL ``` Create API tokens in the LogDeck web UI under **Settings > API Access**. The CLI sends them as `Authorization: Bearer `. Tokens have a scope. **Admin** tokens have full access. **Read-only** tokens can read logs, stats, container details, and events, but cannot mutate anything, use the web terminal, or read container environment variables or settings. That makes them a good fit for CI jobs and AI agents that only need to read. When the server has authentication disabled, no token is needed. On a 401 response, the CLI tells you to authenticate with an API token created in LogDeck Settings, passed with `--token` or `LOGDECK_TOKEN`. ### Resolution order Flags and environment variables override the saved context, which helps in CI or for one-off calls. The URL and the token resolve independently, each from the first source that provides it: 1. Explicit `--url` / `--token` flags 2. `LOGDECK_URL` / `LOGDECK_TOKEN` environment variables 3. The active context from the config file (`--context ` selects another saved context for one invocation) 4. Default `http://localhost:8080` `logdeck status` shows which source supplied the URL and the token. ## Output formats Every command accepts `-o/--output`: - `table` (default): compact aligned columns for humans. - `json`: a single JSON document for one-shot commands, and NDJSON (one JSON object per line) for streaming commands (`logs --follow`, `events`). Timestamps are RFC3339. There are no colors, spinners, prompts, or pagination. ## Commands ### `login` Verify a server connection and save it as the current context. If the server requires authentication and you give no working token, it fails with a hint pointing at Settings. ```bash logdeck login --url https://logdeck.example.com --token ldk_... --name prod ``` ### `context` Manage saved contexts: `list`, `use `, `rm `. ```bash logdeck context list ``` ### `logout` Remove the saved token from the current (or a named) context, keeping its URL. ```bash logdeck logout prod ``` ### `status` Server health, version, and a per-host summary, plus where the connection settings came from (flag, env, or context). Run it first to discover what a server manages. Exits nonzero if the server is unreachable. ```bash logdeck status ``` ### `containers` List containers across all hosts, with optional filters. ```bash logdeck containers --state running --host prod ``` ### `stacks` List Compose projects, grouped by the `com.docker.compose.project` / `io.podman.compose.project` labels, with container counts and hosts. ```bash logdeck stacks ``` ### `inspect` Full inspect data for one container. Table mode shows key facts. `-o json` prints the complete inspect document. ```bash logdeck inspect web -o json ``` ### `logs` Read or follow the parsed logs of a container, or of a whole Compose stack with `--stack`. `--since` and `--until` accept RFC3339 timestamps or relative durations (`30s`, `15m`, `2h`, `1d`). Stack logs merge by timestamp and show the container name on each line. Following a stack covers its first 20 containers, the server's per-request aggregate limit. One-shot stack reads batch beyond that automatically. ```bash logdeck logs web --tail 200 --level ERROR --since 1h logdeck logs web --follow logdeck logs --stack myapp --search "timeout" --since 30m ``` ### `grep` Search the recent logs of every running container across all hosts, merged by timestamp. It looks at the last 15 minutes by default so it stays fast. ```bash logdeck grep "connection refused" --since 1h --level ERROR ``` An empty result still exits 0. Stdout stays empty, so pipelines stay clean, and a one-line hint goes to stderr: `no running containers to search` or `no matches in containers since