Self-hosted library for terminal commands, scripts, and snippets. Browser UI, SQLite, optional AI.
184
Command Center keeps the commands, scripts, snippets, and configuration fragments you would otherwise re-derive from shell history or hunt for in old notes. This image is the self-hosted version. It runs on your own machine or NAS and keeps everything in one SQLite file on a volume you mount. Any browser on your network can reach it.
There is also a desktop app for Linux and Windows. It is the same library features and the same code, just running locally instead of over HTTP.
The two do not sync. Each install owns its library, and Markdown export and import is the only bridge between them. That is a deliberate choice rather than something waiting to be finished.
You need a password of at least 8 characters. The server will not start without one.
docker run -d \
--name command-center \
--restart unless-stopped \
-p 8787:8787 \
-e COMMAND_CENTER_PASSWORD='pick something long' \
-v command-center-data:/var/lib/command-center \
pinkpixeldev/command-center:latest
Open http://<the machine's address>:8787 and sign in.
With Compose:
services:
command-center:
image: pinkpixeldev/command-center:latest
restart: unless-stopped
ports:
- "8787:8787"
environment:
COMMAND_CENTER_PASSWORD: pick something long
volumes:
- command-center-data:/var/lib/command-center
volumes:
command-center-data:
Everything is an environment variable. Only the password is required.
| Variable | Default | What it does |
|---|---|---|
COMMAND_CENTER_PASSWORD | none | The sign-in password. Minimum 8 characters. |
COMMAND_CENTER_PASSWORD_FILE | none | Read the password from a file instead. |
COMMAND_CENTER_DATA_DIR | /var/lib/command-center | The library and the Codex login. Mount this. |
COMMAND_CENTER_ADDR | 0.0.0.0:8787 | Listen address inside the container. |
COMMAND_CENTER_OPENAI_API_KEY | none | Turns on the OpenAI provider. |
COMMAND_CENTER_OPENAI_API_KEY_FILE | none | The same key from a file. Re-read on every use, so rotating it needs no restart. |
COMMAND_CENTER_WEB_DIR | /usr/share/command-center/web | Where the built interface lives. You should not need to change this. |
One volume covers everything. The SQLite library and the Codex login both sit under the data directory, so a container update loses neither.
If you bind-mount a host directory instead of a named volume, it has to be
writable by uid 10001. The container checks this at startup and prints the
exact chown to run when it is not.
A password and a session cookie. The session lasts 30 days and renews on use. Three wrong passwords are free. After that the wait doubles from one second and stops at 30 seconds. Guessing is slow, and you are never locked out of your own library.
Sessions are held in memory, not in the library, so restarting the container signs you out. Signing in again is all there is to it.
The server speaks plain HTTP and expects TLS to be terminated in front of it.
Send X-Forwarded-Proto: https from your proxy and the session cookie is
marked Secure. Without that header it is not, which is what lets a plain LAN
deployment sign in at all. If you expose this beyond your own network, put a
reverse proxy with a certificate in front of it.
The event feed is server-sent events on GET /api/events, so turn response
buffering off for it or live updates arrive in bursts. In nginx that is
proxy_buffering off;.
Both are off until you configure one, and you choose which in Settings. Everything below is optional. The library works without any of it.
OpenAI API key. Set COMMAND_CENTER_OPENAI_API_KEY or point
COMMAND_CENTER_OPENAI_API_KEY_FILE at a file. The server refuses to save a key typed
into the interface, and says so. On a server, the place to change a key is the
container's configuration.
ChatGPT through Codex. The Codex CLI is already in the image. Connect from Settings and choose the sign-in code option. A server has no browser to open, so it gives you a code and a URL instead. Enter them from your phone or laptop. The login lives on the mounted volume, so a restart does not sign you out.
With one of those configured, the app can:
Every request that leaves the machine shows you what is about to be sent first.
GET /api/health needs no password and reports the schema version as well as
liveness, so a server answering while its migrations failed does not read as
healthy. The image has a HEALTHCHECK wired to it already.
curl http://localhost:8787/api/health
Made with 💖 by Pink Pixel
Content type
Image
Digest
sha256:d47130623…
Size
135.9 MB
Last updated
10 days ago
docker pull pinkpixeldev/command-center