A timesaver: see which container is busy, read its logs and stop or start it without typing docker commands, with every key run for real on six sample containers.
▶Prefer to watch? This short video explains what oxker is for, then runs it on a real Ubuntu 24.04 machine with six sample containers, with on-screen captions and no voiceover. Click to play, or watch it on YouTube.
oxker: a terminal screen for your Docker containers. It lists them live and lets you act on them.
oxker start it (it reads the Docker socket)
j k / 4 0 move; sort by CPU; stop sorting
Tab, j, Enter go to the command menu, pick a command, run it
i e s h q inspect, shell, save logs, help, quit
oxker is a terminal user interface for Docker. One screen shows every container with its state, CPU and memory, the logs of the selected container, and graphs of its CPU, memory and network traffic, all updating once a second. From the keyboard you can sort and filter the list, look at a container's full Docker details, open a shell inside it, save its logs to a file, and stop, start, restart or delete it. It saves typing docker ps, docker logs, docker stats and docker stop in turn, and it works over SSH on a server because it only needs to talk to the Docker socket.
This page is the written version of the Timesavers video. Every key below was run for real, in an Ubuntu 24.04 container that runs its own Docker daemon, with oxker 0.13.4 and six sample containers (a web server, a small API, a database, a worker that prints a line every two seconds, a CPU-burning loop and a finished job). The screens shown are the real screens from that run, at one moment. A page cannot show a screen that updates every second, so watch the video for that. The section "What was not run" lists the keys and options that were not tried.
What oxker is for
Use oxker when you are on a Docker host and want to look first and act second:
which container is busy? the cpu column, sortable, with a graph for the selected one
what is it saying? the logs panel follows the selection, no docker logs needed
what is it exactly? inspect shows the full Docker details of the container
stop it, start it again the command menu, from the keyboard
get a shell in it e, then exit to come back
keep its logs s saves them to a file in your home folder
It does not replace docker compose, a monitoring system or your orchestrator. It shows one host's Docker daemon, and it is for looking and for quick actions. It is a small program (about 4.6 MB in the lab) written in Rust, under the MIT licence (from its README).
Install and the sample containers
The project's README gives several routes (cargo, Docker, Nix, the AUR, Homebrew, release files) and an install script. The script is short, so read it before you run it: it works out your CPU type, downloads the latest release tarball from GitHub, unpacks the one binary and installs it into ~/.local/bin. It does not check a checksum, so if that matters, download the release yourself and check it. The lab used it:
$ curl -fsSL https://raw.githubusercontent.com/mrjackwills/oxker/main/install.sh -o install.sh
$ bash install.sh
$ oxker --version
oxker 0.13.4
oxker needs access to the Docker socket (/var/run/docker.sock by default, or the host in --host or DOCKER_HOST). The lab user could use the socket, so nothing else was needed. The sample containers (built for this page, nothing in them is real):
$ docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
NAMES IMAGE STATUS
old-job alpine:3.21 Exited (0) 3 minutes ago
busy alpine:3.21 Up About a minute
worker alpine:3.21 Up 3 minutes
db postgres:16 Up 3 minutes
api python:3.13-slim Up 3 minutes
web nginx:alpine Up 3 minutes
web is nginx with a request every second, and half of those requests are for a page that does not exist, so its log shows 404s. busy runs a loop that uses a full CPU core. worker prints a line every two seconds. old-job ran once and exited.
The main screen
Start it with oxker. The first screen is the whole tool:
$ oxker
name state status cpu memory/limit id ( h ) show help
โญ Containers 1/6 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโญโโโโโโโโโโโฎ
โโช api โ running Up 22 seconds 00.02% 16.61 MB / 33.32 GB 41f03964 python:โโโถ pause โ
โ db โ running Up 22 seconds 00.04% 21.39 MB / 33.32 GB 30c9a267 postgreโโ restart โ
โ web โ running Up 23 seconds 00.07% 9.18 MB / 33.32 GB e1a5beb4 nginx:aโโ stop โ
โ busy โ running Up 21 seconds 101.44% 368.64 kB / 33.32 GB c6a1fecc alpine:โโ delete โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโฏ
โญ Logs - api - python:3.13-slim โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ no logs found โ
โ โ
โ โ
โ โ
โ โ
โ โ
โ โ
โ โ
โ โ
โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
โญโโโโโโโโ cpu 00.02% โโโโโโโโโฎโญโโโโโ memory 16.61 MB โโโโโโฎโญโโ rx: 0 kb/s tx: 0 kb/s โโโโฎ โญโโโโโโโโโ ports โโโโโโโโโโโฎ
โ00.02%โ โโ16.61 MBโโขโข โโ โ โ โ no ports โ
โ โโขโขโข โโ โ โโ0 kb/sโ โ โ โ
โ โโขโข โโ โ โโ0 kb/sโ โ โ โ
โ โ โโ โ โโ โโขโข โ โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
From the top: a header line with the column names (name, state, status, cpu, memory and limit, id, image) and a reminder that h shows help. Below it the Containers panel, one row per container, with the selected one marked, and to its right the command menu (pause, restart, stop, delete). Under that the Logs panel for the selected container. At the bottom four small panels: a CPU graph, a memory graph, network receive and transmit rates, and the container's ports. Everything refreshes about once a second (-d sets the interval, and one second is the lowest it goes).
The container list shows four rows at a time and scrolls. The number at the top left of the panel, Containers 1/6, is the position of the selection and the total. A container that has exited, like old-job, is listed with โ exited and a status such as Exited (0).
Move, sort and filter
j and k (or the arrow keys) move the selection, and the logs and graphs below follow it. A number key sorts by that heading, counting the columns from 1, so 4 is cpu. Press it again to reverse the order, and 0 to stop sorting. After a sort the selection stays on the same container, so the list may scroll away from the top. Home jumps to the first row. Here 4, then 4 again, then Home:
keys: 4 4 Home
name state status cpu โผ memory/limit id ( h ) show help
โญ Containers 1/6 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโญโโโโโโโโโโโฎ
โโช busy โ running Up 33 seconds 101.34% 368.64 kB / 33.32 GB c6a1fecc alpine:โโโถ pause โ
โ worker โ running Up 34 seconds 00.16% 1.08 MB / 33.32 GB 0117979a alpine:โโ restart โ
โ web โ running Up 35 seconds 00.09% 9.19 MB / 33.32 GB e1a5beb4 nginx:aโโ stop โ
โ db โ running Up 34 seconds 00.04% 23.42 MB / 33.32 GB 30c9a267 postgreโโ delete โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโฏ
The arrow in the heading (cpu โผ) shows the sort column and direction, and busy, at 101%, is at the top.
/ opens the filter. Type a word and press Enter, and only the matching containers stay (Containers 1/1 - filtered). The prompt at the bottom of the screen offers Name, Image, Status and All, chosen with the left and right arrows. The filter is not cleared by Esc after you have applied it. In the lab, pressing / and then Esc left the filter in place. What cleared it was pressing /, deleting the text with Backspace, and pressing Enter:
keys: / web Enter
name state status cpu memory/limit id ( h ) show help
โญ Containers 1/1 - filtered โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโญโโโโโโโโโโโฎ
โโช web โ running Up 42 seconds 00.09% 9.19 MB / 33.32 GB e1a5beb4 nginx:aโโโถ pause โ
โ โโ restart โ
โ โโ stop โ
โ โโ delete โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโฏ
The filter changes which containers are listed, and nothing else: the selection, the logs and the graphs work on the container that is left.
Logs and graphs
The Logs panel shows the output of the selected container, newest at the bottom, with the timestamp Docker gave each line (-t takes the timestamps off). Tab moves the focus between the panels (containers, then the command menu, then the logs, then around again), and the focused panel has a bright border. In the lab Tab went to the command menu first. The README says the up and down keys scroll the selected panel. A container with no output, like busy, says no logs found. This is the Logs panel for web, which has a request every second, half of them for a page that does not exist:
$ (filter on web, the Logs panel)
โญ Logs 137/137 - web - nginx:alpine โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ 2026-10-20T17:28:57.12811442 172.18.0.1 - - [20/Oct/2026:17:28:57 +0000] "GET /missing HTTP/1.1" 404 153 "-" "curlโ
โ 2026-10-20T17:28:58.14417304 172.18.0.1 - - [20/Oct/2026:17:28:58 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.5.0"โ
โ 2026-10-20T17:28:58.15989619 2026/10/20 17:28:58 [error] 34#34: *72 open() "/usr/share/nginx/html/missing" failed โ
โ 2026-10-20T17:28:58.15991413 172.18.0.1 - - [20/Oct/2026:17:28:58 +0000] "GET /missing HTTP/1.1" 404 153 "-" "curlโ
โ 2026-10-20T17:28:59.17698659 172.18.0.1 - - [20/Oct/2026:17:28:59 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.5.0"โ
โ 2026-10-20T17:28:59.19221015 2026/10/20 17:28:59 [error] 35#35: *74 open() "/usr/share/nginx/html/missing" failed โ
โ 2026-10-20T17:28:59.19224918 172.18.0.1 - - [20/Oct/2026:17:28:59 +0000] "GET /missing HTTP/1.1" 404 153 "-" "curlโ
โ 2026-10-20T17:29:00.21039394 172.18.0.1 - - [20/Oct/2026:17:29:00 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.5.0"โ
โ 2026-10-20T17:29:00.22599022 2026/10/20 17:29:00 [error] 35#35: *76 open() "/usr/share/nginx/html/missing" failed โ
โโถ 2026-10-20T17:29:00.22604273 172.18.0.1 - - [20/Oct/2026:17:29:00 +0000] "GET /missing HTTP/1.1" 404 153 "-" "curlโ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 0/127 โ โฏ
Each line is the timestamp, then the container's own log line: an nginx access line, or an error line for the missing page. The panel title shows the container, its image and the line position (137/137 here).
- and = make the logs panel smaller and larger, and \ hides it. # starts a log search. In the lab the prompt for it opened ("Esc clear search term:"), but the term typed by the recording script did not appear in the prompt, so searching the logs was not completed and is listed under "What was not run".
Inspect a container
i opens the inspect view: the full JSON that docker inspect would print, in a scrollable panel with the line position at the bottom. j and k scroll, and Esc (or c, or i again) closes it:
keys: i jjjjjj
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ inspecting: api 41f03964 - c or Esc or i to exit โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ "8000" โ
โ ], โ
โ "State": { โ
โ "Status": "running", โ
โ "Running": true, โ
โ "Paused": false, โ
โ "Restarting": false, โ
โ "OOMKilled": false, โ
โ "Dead": false, โ
โ "Pid": 606, โ
โ "ExitCode": 0, โ
โ "Error": "", โ
โ "StartedAt": "2026-10-20T17:28:18.550571223Z", โ
โ "FinishedAt": "0001-01-01T00:00:00Z" โ
โ }, โ
โ "Image": "sha256:7c61056e61ac89e852de05f3dc6fa51a6dd2181797bceed46aa725dd7cb2cd3b", โ
โ "ResolvConfPath": "/var/lib/docker/containers/41f039645871718adbe9e681f09eaca6a3066ae0e9f44d9ec07935c0d0cf8db0/resโ
โ "HostnamePath": "/var/lib/docker/containers/41f039645871718adbe9e681f09eaca6a3066ae0e9f44d9ec07935c0d0cf8db0/hostnโ
โ "HostsPath": "/var/lib/docker/containers/41f039645871718adbe9e681f09eaca6a3066ae0e9f44d9ec07935c0d0cf8db0/hosts", โ
โ "LogPath": "/var/lib/docker/containers/41f039645871718adbe9e681f09eaca6a3066ae0e9f44d9ec07935c0d0cf8db0/41f0396458โ
โ "Name": "/api", โ
โ "RestartCount": 0, โ
โ "Driver": "overlayfs", โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ 6/164 โ 0/65 โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
This is the quickest way to see a container's mounts, environment, restart policy or network settings without leaving the screen. The header of the panel names the container and its short id.
Stop and start a container
The command menu is the small panel to the right of the list. Its entries depend on the container's state: a running container offers pause, restart, stop and delete, and an exited one offers start, restart and delete. The arrow in front of the first entry shows the selected command. Tab moves the focus into the menu, j and k move the arrow, and Enter runs the command.
To stop busy, filter to it, press Tab, press j twice (pause, restart, stop) and press Enter. A spinner shows in the header while Docker works, and then:
keys: / busy Enter, Tab j j Enter
name state status cpu memory/limit ( h ) show help
โญ Containers 1/1 - filtered โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโญโโโโโโโโโโโฎ
โโช busy โ exited Exited (0) 3 seconds ago 00.00% 0.00 kB / 0.00 kB c6a1fecc alpiโโโถ start โ
โ โโ restart โ
โ โโ delete โ
โ โโ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโฏ
State โ exited, status Exited (0), CPU 0.00%. The first command in the menu is now start. Press Enter again and the container runs again, with its CPU back at about 100%:
keys: Enter
name state status cpu memory/limit ( h ) show help
โญ Containers 1/1 - filtered โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎโญโโโโโโโโโโโฎ
โโช busy โ running Up 4 seconds 101.20% 835.58 kB / 33.32 GB c6a1fecc alpโโโถ pause โ
โ โโ restart โ
โ โโ stop โ
โ โโ delete โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโฏ
stop asks Docker to stop the container the usual way, which sends it SIGTERM and waits for its grace period (10 seconds unless it was changed) before it is killed. In the lab busy handles SIGTERM and stopped in about three seconds. In an earlier run its loop ignored the signal, oxker showed the spinner and the container was still running several seconds later. Delete was not run, and neither were pause and restart.
A shell inside a container
e opens a shell in the selected container. oxker can do this with the Docker API or with the docker command (--use-cli). With the filter on worker, pressing e gave a shell, and exit returned to oxker:
$ oxker --use-cli
keys: / worker Enter, e
/ # hostname
0117979aa7ff
/ #
With --use-cli the shell appeared in about two seconds and exit took the lab straight back to oxker. Without the flag (exec through the API) the shell also worked, but after exit oxker came back only after about twenty seconds in both tries in the lab, so the guide and the video use --use-cli. The shell is whatever the image has: this one is the busybox shell of Alpine. It needs the container to be running, and exec is not available on Windows (from the README).
Save the logs
s writes the logs of the selected container to a file. The file goes to your home folder, or to --save-dir, and is named after the container and a number (the time as seconds since 1970). The screen says so for a moment:
keys: / web Enter, s
โ โ โขโข โโ โ โโ33.32 kb/โ
โ โ โโ โ โโ โ saved to /home/ubuntu/web_1792517393.log
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏโฐโโโโโโโโโโ
Leave oxker with q and look at the file. It is plain text, one log line per line, each starting with the timestamp Docker recorded:
$ ls web_*.log
$ head -2 web_*.log
web_1792517393.log
ubuntu@timesaver:~$ head -2 web_*.log | cut -c1-100
2026-10-20T17:28:18.401420229Z /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attem
2026-10-20T17:28:18.401458027Z /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoin
ubuntu@timesaver:~$
(The lines are cut to 100 characters here.) Save before you stop or delete a container: the logs of a deleted container are gone.
The keys on the help screen
h opens the help, with the oxker logo, its version, the folder logs are exported to, the time zone of the log timestamps and the keymap, and h or Esc closes it. The keymap as the lab's help screen printed it:
q quit c Esc close dialog
Down Up j k Home End scroll vertically Left Right scroll horizontally
Control increase scroll speed Enter send docker command
e exec into a container i container inspect mode
/ F1 filter mode # log search mode
h toggle this panel f force clear screen and redraw
- = change log section height \ toggle of section visibility
0 1 ~ 9 sort by header - or click header 0 stop sort
Tab Back Tab change panel m toggle mouse capture - allows text selection
s save logs to file
The README says the mouse also works (clicking a panel selects it, clicking a heading sorts), and that m turns mouse capture off, so you can select text with the mouse. The mouse was not used in the lab.
Command line options
oxker --help lists the options of the version in the lab:
A simple tui to view & control docker containers
Usage: oxker [OPTIONS]
Options:
-d <ms> Docker update interval in ms, minimum effectively 1000 [default: 1000]
-t Remove timestamps from Docker logs
-c Attempt to colorize the logs, conflicts with "-r"
-r Show raw logs, default is to remove ansi formatting, conflicts with "-c"
-s Show self when running as a docker container
-g Don't draw gui - for debugging - mostly pointless
--host <HOST> Docker host, defaults to `/var/run/docker.sock`
--no-stderr Do not include stderr output in logs
--timezone <TIMEZONE> Display the container logs timestamp with a given timezone, default is UTC
--save-dir <SAVE_DIR> Directory for saving exported logs, defaults to `$HOME`
--config-file <CONFIG_FILE> Path to a config file, readable as TOML, JSONC, or JSON
--use-cli Force use of docker cli when execing into containers
-h, --help Print help
-V, --version Print version
Command-line options win over the config file. oxker creates a config.toml in your local config folder the first time (from the README), where the keymap and colours can be changed. The config file was not opened in the lab.
What was not run in the lab
Log search (#): the prompt opened, but the search itself was not completed. Pause, restart and delete from the command menu. The sort keys other than 4 and 0, the filter modes by image and by status, the -, = and \ keys for the logs panel, f (redraw), m (mouse capture), horizontal scrolling and the Control key for faster scrolling. The options -d, -t, -c, -r, -s, -g, --host, --no-stderr, --timezone, --save-dir and --config-file, and the config file itself. Exec through the API was run, but only to see how slowly it came back; --use-cli was used for the demo. The install routes other than the script (cargo, Docker, Nix, AUR, Homebrew, .deb files). A Docker host that is not the local socket, many containers (the list was six), and containers with a lot of log output. Windows and macOS. Everything ran in an Ubuntu 24.04 container with Docker inside, with oxker 0.13.4.
Common problems and tips
I pressed Esc and the filter is still there. Esc closes dialogs, but an applied filter stays. Press /, delete the text with Backspace, and press Enter.
After exit from a shell oxker does not come back. Exec through the Docker API took about twenty seconds to return in the lab. Start oxker with --use-cli.
The list does not show all my containers. It shows four rows and scrolls. Look at the number in the panel title (Containers 3/6), or filter. Exited containers are listed too.
Stop seems stuck. docker stop waits for the container's grace period when the program ignores SIGTERM. The spinner in the header means Docker is still working.
I see a permission error. oxker needs access to the Docker socket. The user must be in the docker group (or the socket must be reachable some other way), as for the docker command itself.
Tips. Sort by cpu first (4, then 4 again) when something is slow, and check the logs of the one at the top. Use i before you change anything, to see what the container really is. Press s before you stop or delete a container whose logs you may want. And remember that oxker shows what Docker knows: if a container is healthy inside and broken outside, the answer is in your network and your application, not in this screen.