Skip to content

ajphilton/caddy-tui

Repository files navigation

caddy-tui

An interactive terminal UI plus CLI toolkit (built with Colorama + Rich) that keeps Caddy configuration in SQLite (~/.caddy-tui/config.db), lets you inspect/import data, offers inline block editing, and safely regenerates validated configs before reloading the Caddy service.

Project structure

caddy-tui/
├── caddy_tui/
│   ├── cli.py                # Click-based CLI skeleton & entry points
│   ├── tui_app.py            # Rich/Colorama TUI loop
│   ├── db.py                 # Schema builder + session helpers
│   ├── importer.py           # Caddyfile → snapshot pipeline
│   ├── exporter.py           # Snapshot → Caddyfile renderer
│   ├── block_editor.py       # CRUD helpers for caddy-tui snapshot blocks
│   ├── drift.py, status.py   # Diff + reporting utilities
│   └── ...                   # Additional helpers (config, models, etc.)
├── pyproject.toml            # PyPI metadata + console scripts
├── MANIFEST.in               # Source distribution manifest
├── README.md                 # Usage + architecture guide
├── CHANGELOG.md              # Release notes
└── LICENSE                   # MIT terms

The modules are intentionally decoupled so you can script against the importer/exporter hooks or database builder without invoking the CLI.

Quick start

pip install -e .
caddy-tui init                # DB schema builder
sudo caddy-tui import --caddyfile /etc/caddy/Caddyfile
caddy-tui tui                 # Interactive block editor + drift monitor

Install from PyPI

You can install the published package directly (recommended inside a virtualenv):

pip install --upgrade caddy-tui

Need a globally available CLI without touching the system Python? Use pipx:

pipx install caddy-tui

This installs both caddy-tui and the optional caddy-tui-helper command. If you want the helper to run via sudo without a password, follow the “Privileged helper” section below to add it to /etc/sudoers.d/caddy-tui.

The CLI prints JSON so it can slot straight into scripts, CI jobs, or other automation.

Core commands

Command Purpose
caddy-tui init Create the SQLite schema at ~/.caddy-tui/config.db.
caddy-tui import --caddyfile PATH Parse an existing Caddyfile and load it into the DB. Use sudo when PATH lives under /etc/caddy.
caddy-tui list-sites / add-site / remove-site Manage site definitions directly from the CLI.
caddy-tui apply Regenerate a Caddyfile from the DB, validate it, and reload Caddy via systemctl reload caddy (run with sudo).
caddy-tui refresh-live Force a fresh snapshot of the live Caddyfile via the configured helper (same action as the TUI “Refresh live snapshot” option).
caddy-tui status [--caddyfile PATH] [--diff] [--refresh-live] Compare the DB-rendered config with the specified Caddyfile (defaults to the last imported path). Pass --refresh-live to mirror the live file just before comparing. Exits with code 1 when drift is detected.
caddy-tui tui Launch the interactive scrolling menu for importing files, editing caddy-tui blocks (add/edit/delete), refreshing the live snapshot, reviewing drift, and checking Caddy service health.

CLI skeleton & starter commands

  • caddy_tui/cli.py defines a single Click group (main) plus entry points for init/import/apply/status/refresh-live/tui/validate/version. Each command simply marshals arguments then calls the relevant helper module, so you can copy the file as a starter CLI scaffold for other admin scripts.
  • Every command emits JSON so shell automation stays predictable—check the status field and inspect payload keys for details.
  • New commands should live in dedicated helper modules (example: drift.compare_caddyfile) and then be wired into the CLI via a short @main.command() block.

Status command

Use caddy-tui status --diff (typically with sudo) to verify the live /etc/caddy/Caddyfile still matches the SQLite data. The tool prints hashes, whether everything is in sync, and a truncated unified diff when requested. This is handy in CI or cron to catch manual edits. When --refresh-live is set the helper mirrors /etc/caddy/Caddyfile, computes the comparisons, and immediately purges the live snapshot from SQLite so sensitive data is not stored after the check completes.

Importing system Caddyfiles

Most distro packages restrict /etc/caddy/Caddyfile to root. Keep the TUI unprivileged and run imports as needed via:

sudo /home/alexander_skystamper_com/projects/caddy-tui/.venv/bin/caddy-tui import --caddyfile /etc/caddy/Caddyfile

The database directory honours SUDO_USER, so the sudo-run import updates the same ~/.caddy-tui/config.db that the TUI uses.

Privileged helper (optional)

If you prefer to grant finely scoped permissions instead of full sudo caddy-tui, install the accompanying helper entry point:

sudo visudo -f /etc/sudoers.d/caddy-tui
# Allow your user to run the helper without a password
alexander  ALL=(ALL) NOPASSWD: /usr/local/bin/caddy-tui-helper

caddy-tui-helper exposes mirror/install/reload plus two extra commands: status (wraps systemctl is-active caddy by default) and restart (wraps systemctl restart caddy). When the TUI hits a permission error it prints the exact helper command (e.g. sudo caddy-tui-helper mirror --source /etc/caddy/Caddyfile ...) so you can re-run it immediately or let sudoers execute it without a prompt.

The helper runner resolves the executable to an absolute path before invoking sudo, so as long as which caddy-tui-helper works in your shell you do not need to export CADDY_TUI_HELPER_BIN. Just copy that which output into the sudoers entry (alexander ALL=(ALL) NOPASSWD: /home/.../.venv/bin/caddy-tui-helper) so sudo can locate the same binary.

Admin API probe

Set CADDY_TUI_ADMIN_ENDPOINT (defaults to http://127.0.0.1:2019/config) if your Caddy admin API listens elsewhere. The TUI/CLI will fetch live status from this endpoint on every refresh, report whether the service is up, and (when the endpoint returns text/caddyfile) mirror the running config straight into the short-lived caddy_live snapshot before diffing. The snapshot is purged immediately after comparisons so sensitive live data never lingers in SQLite.

Interactive menu overview

caddy-tui tui prints a repeating block in this order:

  1. Result of the previous selection (e.g. import success, drift diff panel).
  2. A Rich table that captures database readiness, stored block count, last import path, drift summary for every snapshot source (caddy-tui, Caddyfile, live helper), and a color-coded line for the Caddy service state (green when live+in-sync, orange when live but drifting, red when down, yellow when unknown).
  3. A context-aware menu. Options currently include:
    • f – Write the privileged Caddyfile back into caddy-tui (helper-assisted import so sudo can mirror /etc/caddy/Caddyfile).
    • t – Write the current caddy-tui snapshot over the system Caddyfile (helper-assisted install when write permissions are missing).
    • r – Refresh the live snapshot (polls the Caddy admin API for content first, falling back to the helper mirror only when the API is unavailable).
    • p – Print the live Caddyfile exactly as Caddy is serving it. The TUI refreshes the live snapshot, renders every block, and shows the full text inside a scrollable Rich panel so you can copy/paste or audit directives without leaving the menu.
    • b – Show the block contents for each snapshot side-by-side (caddy-tui, Caddyfile, and live) in a dedicated table with wrapped text so you can visually compare directives.
    • n / e / x – Add, edit, or delete blocks inside the caddy-tui snapshot. The TUI opens your $EDITOR (or nano/vi fallback), validates the single-block snippet, and persists it back to SQLite so caddy-tui tui is the one-stop shop for CRUD.
    • c – Reload Caddy through the helper and automatically queue a live snapshot refresh afterwards (shown when the helper reports Caddy is live).
    • s – Restart Caddy through the helper when the status probe reports the service is down.
    • d – Show the unified diff between the DB-rendered config and /etc/caddy/Caddyfile (available once an import path exists). The diff is shown inside a Rich panel and can be copied directly from the terminal scrollback.
    • h – Show an in-app CLI reference table listing every caddy-tui command, its usage string, and a concise description so you can jump into automation or remind yourself of available flags without leaving the interface.
    • u – When GitHub publishes a newer release, this option appears and prints upgrade instructions with both pip install --upgrade caddy-tui and pipx upgrade caddy-tui so you can follow the workflow you originally used.
    • q – Quit the session.

Every action prints the exact helper command when elevated access is required, so you can copy/paste or add it to sudoers immediately.

Database schema builder

caddy-tui init (or python -m caddy_tui.db) runs caddy_tui.db.init_db, which:

  1. Ensures ~/.caddy-tui/ exists (or honours --db PATH).
  2. Applies the SQLAlchemy schema declared in caddy_tui/models.py.
  3. Seeds baseline Config + snapshot rows so importer/exporter hooks always have a target.

The command is idempotent, so you can re-run it whenever you ship a new version or want to bootstrap a fresh environment.

Import/export hooks

  • caddy_tui.importer.import_caddyfile mirrors an existing Caddyfile into SQLite. Pass target_snapshot (defaults to caddyfile) and mirror_to to control where parsed blocks land, or pass helper_interactive=True to log the helper command when elevated access is required.
  • caddy_tui.exporter.generate_caddyfile renders the caddy-tui snapshot back to a canonical Caddyfile and calls caddy adapt as needed. The helper cooperates with drift.compare_caddyfile so diffing against arbitrary files stays consistent.
  • caddy_tui.block_editor exposes load_caddy_tui_blocks, save_caddy_tui_blocks, and parse_single_block for fine-grained CRUD that matches what the TUI uses.

Integrate those helpers directly from Python (no Click dependency) whenever you need to script imports/exports outside of the bundled CLI.

Example workflow

  1. Initialise the DB: caddy-tui init.
  2. Import the live config: sudo caddy-tui import --caddyfile /etc/caddy/Caddyfile.
  3. Launch caddy-tui tui, edit sites, and review status messages (use r whenever you need a fresh live snapshot).
  4. Apply and reload: sudo caddy-tui apply (the CLI auto-queues a live snapshot refresh afterward, or run caddy-tui refresh-live to grab a short-lived snapshot of /etc/caddy/Caddyfile that is purged once the comparison completes).
  5. Keep an eye on drift: sudo caddy-tui status --diff --refresh-live in CI or a nightly cron.

How to run locally

python3 -m venv .venv
source .venv/bin/activate
pip install -e .[test]
pytest
caddy-tui tui

Run privileged steps (import/apply/status) with sudo, but keep the interactive menu under your normal user account.

Publishing to PyPI

CI now handles almost everything:

  1. Update docs/changelog and bump pyproject.toml + caddy_tui/__init__.py.
  2. Commit to main and push. The build job runs plus publish-to-testpypi, so TestPyPI always mirrors main.
  3. Tag the release (git tag v0.2.2 && git push origin v0.2.2). GitHub pauses the publish-to-pypi job until the pypi environment is approved; once approved, PyPI receives the artifacts.

Local uploads are still possible when you need to hotfix outside CI:

python -m build
twine upload dist/*

The wheel exposes both CLI entry points (caddy-tui, caddy-tui-helper) and ships all helper modules for downstream automation.

Wishlist

  • CLI deep dive for AI assistants – expand the Click command surface (status filters, automation-friendly outputs, helper diagnostics) so Copilot/Codex-style agents can treat caddy-tui as a powerful scripting target. Document each addition in the changelog to keep the roadmap transparent.

About

TUI for Caddy management

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors

Languages