CLI for managing a home-server hosting platform backed by Cloudflare Tunnel, Traefik, and Docker Compose.
Project description
Home Server Controller (homesrvctl)
MIT licensed.
homesrvctl is a production-oriented Python CLI for operating a home-server hosting platform built around:
- Cloudflare DNS and Cloudflare Tunnel
cloudflared- Traefik
- Docker Compose
- a shared external Docker network, typically
web
It helps with the repeatable operator work around self-hosted sites:
- bootstrap a first Debian-family Raspberry Pi host
- create or inspect the shared Cloudflare Tunnel setup
- add and repair apex plus wildcard domain routes
- reconcile local
cloudflaredingress entries - scaffold static sites and app stacks
- start, stop, validate, and diagnose per-hostname Compose stacks
- inspect the platform through a Textual terminal dashboard
Operating Model
homesrvctl intentionally keeps the hosting model simple:
- Cloudflare Tunnel handles domain-level ingress.
- Traefik handles local hostname routing.
- Docker Compose runs each site or app.
- Once
example.comand*.example.compoint at the tunnel, additional subdomains usually only need local server changes.
For an already-built platform, homesrvctl manages domains, scaffolds, validation, and local operations. For the first supported fresh-host path, the shipped bootstrap commands can converge Docker, Compose, Traefik, cloudflared, shared directories, service wiring, a Cloudflare tunnel, and the main config as explicit operator-run slices.
homesrvctl is not a full infrastructure-as-code framework, a generic app generator, a Docker/Traefik replacement, or a broad Cloudflare administration console.
Installation
From PyPI:
pipx install homesrvctl
Upgrade an existing PyPI install:
pipx upgrade homesrvctl
If pipx reports that ~/.local/bin/homesrvctl already exists and is not the expected pipx symlink, inspect the active command path:
homesrvctl version --json
homesrvctl install status
From a tagged GitHub release:
pip install "homesrvctl @ https://github.com/Broda/homesrvctl/archive/refs/tags/vX.Y.Z.tar.gz"
For local development:
python -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
The published Python distribution name is homesrvctl. The CLI command is also homesrvctl.
Documentation
Detailed operator guides live in the project wiki:
- Wiki home:
https://github.com/Broda/homesrvctl/wiki - Getting started:
https://github.com/Broda/homesrvctl/wiki/Getting-Started - Bootstrap plan:
https://github.com/Broda/homesrvctl/wiki/Bootstrap-Plan - Configuration:
https://github.com/Broda/homesrvctl/wiki/Configuration - Domain workflow:
https://github.com/Broda/homesrvctl/wiki/Domain-Workflow - Tunnel inspection:
https://github.com/Broda/homesrvctl/wiki/Tunnel-Inspection - Terminal dashboard:
https://github.com/Broda/homesrvctl/wiki/Terminal-Dashboard - Release process:
https://github.com/Broda/homesrvctl/wiki/Release-Process
Repo-maintenance docs:
PROJECT_CONTEXT.mdrecords scope, assumptions, and verification commands.ARCHITECTURE.mdrecords module boundaries and public contracts.ROADMAP.mdrecords current and proposed work.CHANGELOG.mdrecords user-facing changes.RELEASING.mdrecords the tagged release process.
Quick Start
Create and inspect the config:
homesrvctl config init
homesrvctl config show
Bootstrap a first supported Debian-family host:
homesrvctl bootstrap assess
sudo homesrvctl bootstrap runtime
homesrvctl bootstrap tunnel --account-id <cloudflare-account-id>
sudo homesrvctl bootstrap wiring
homesrvctl bootstrap validate
Scaffold and run a static site:
homesrvctl domain add example.com --restart-cloudflared
homesrvctl site init example.com
homesrvctl up example.com
homesrvctl doctor example.com
Scaffold an app stack:
homesrvctl app init app.example.com --template node
homesrvctl up app.example.com
homesrvctl doctor app.example.com
Stop and delete a local stack directory:
homesrvctl cleanup test.example.com --dry-run
homesrvctl cleanup test.example.com --force
Launch the terminal dashboard:
homesrvctl
The explicit dashboard command is also available:
homesrvctl tui
Configuration Summary
The default config path is:
~/.config/homesrvctl/config.yml
Default config shape:
tunnel_name: homesrvctl-tunnel
sites_root: /srv/homesrvctl/sites
docker_network: web
traefik_url: http://localhost:80
cloudflared_config: /srv/homesrvctl/cloudflared/config.yml
cloudflare_api_token: ""
profiles: {}
The first-class shared cloudflared setup model uses:
- config:
/srv/homesrvctl/cloudflared/config.yml - tunnel credentials JSON:
/srv/homesrvctl/cloudflared/<tunnel-id>.json - ownership:
root:homesrvctl - permissions:
- directory
750 - files
640
- directory
The tunnel credentials JSON is secret material. Use the dedicated homesrvctl group for trusted operator access rather than making credentials world-readable.
The intended permission model is one-time privileged bootstrap followed by non-root operation. bootstrap runtime creates the shared group and group-writable stack/config directories, and bootstrap wiring installs systemd wiring plus a narrow sudoers rule that lets homesrvctl group members restart or reload only the cloudflared service. Log out and back in after group membership changes so the current shell picks up homesrvctl and docker access.
For the shipped bootstrap Traefik runtime, traefik_url should target the public web entrypoint on host port 80. Host port 8081 is reserved for the Traefik dashboard/API and should not be used as the Cloudflare Tunnel ingress target.
cloudflare_api_token may also be supplied through CLOUDFLARE_API_TOKEN. Domain management needs Zone:Read and DNS:Edit. Tunnel inspection and bootstrap tunnel provisioning need the relevant Cloudflare Tunnel account permissions.
Routing precedence is:
- Global defaults from top-level
docker_networkandtraefik_url. - Named profile values from
profiles. - Direct stack-local overrides from
/srv/homesrvctl/sites/<hostname>/homesrvctl.yml.
Supported stack-local keys:
profile: edge
docker_network: edge
traefik_url: http://localhost:9000
Common Workflows
Inspect host and tunnel state:
homesrvctl validate
homesrvctl tunnel status
homesrvctl cloudflared status
homesrvctl cloudflared setup
homesrvctl cloudflared config-test
homesrvctl cloudflared logs
Manage a domain:
homesrvctl domain add example.com --restart-cloudflared
homesrvctl domain status example.com
homesrvctl domain repair example.com --dry-run
homesrvctl domain repair example.com --restart-cloudflared
homesrvctl domain remove example.com --dry-run
Scaffold common stack types:
homesrvctl site init example.com
homesrvctl app init app.example.com --template static
homesrvctl app init portal.example.com --template static-api
homesrvctl app init api.example.com --template python
homesrvctl app init web.example.com --template node
homesrvctl app init blog.example.com --template jekyll
homesrvctl app init product.example.com --template rust-react-postgres
Use routing overrides:
homesrvctl site init example.com --profile edge
homesrvctl app init app.example.com --template node --docker-network edge
homesrvctl app init api.example.com --template python --traefik-url http://localhost:9000
Override template ports where supported:
homesrvctl app init app.example.com --template node --port app=3100
homesrvctl app init portal.example.com --template static-api --port api=8100
homesrvctl ports list --stack portal.example.com
Preview mutations and consume JSON:
homesrvctl domain add example.com --dry-run --json
homesrvctl app init app.example.com --template node --dry-run --json
homesrvctl up app.example.com --dry-run --json
homesrvctl validate --json
All JSON commands include a top-level schema_version.
Command Overview
homesrvctl config init [--path PATH] [--force] [--json]homesrvctl config show [--path PATH] [--stack HOSTNAME] [--json]homesrvctl bootstrap assess [--path PATH] [--json]homesrvctl bootstrap runtime [--path PATH] [--operator-user USER] [--force] [--dry-run] [--json]homesrvctl bootstrap tunnel [--path PATH] [--account-id ACCOUNT_ID] [--name NAME] [--force] [--json]homesrvctl bootstrap wiring [--path PATH] [--force] [--dry-run] [--json]homesrvctl bootstrap validate [--path PATH] [--json]homesrvctl tunnel status [--json]homesrvctl domain add <domain> [--dry-run] [--json] [--restart-cloudflared]homesrvctl domain status <domain> [--json]homesrvctl domain repair <domain> [--dry-run] [--json] [--restart-cloudflared]homesrvctl domain remove <domain> [--dry-run] [--json] [--restart-cloudflared]homesrvctl site init <hostname> [--force] [--dry-run] [--json] [--profile NAME] [--docker-network NETWORK] [--traefik-url URL]homesrvctl app init <hostname> [--template static|static-api|placeholder|node|python|jekyll|rust-react-postgres] [--port NAME=PORT]... [--force] [--dry-run] [--json] [--profile NAME] [--docker-network NETWORK] [--traefik-url URL]homesrvctl ports list [--stack HOSTNAME] [--json]homesrvctl up <hostname> [--dry-run] [--json]homesrvctl down <hostname> [--dry-run] [--json]homesrvctl restart <hostname> [--dry-run] [--json]homesrvctl list [--json]homesrvctl tui [--refresh-seconds FLOAT]homesrvctl cloudflared status [--json]homesrvctl cloudflared setup [--json]homesrvctl cloudflared config-test [--json]homesrvctl cloudflared logs [--follow] [--json]homesrvctl cloudflared restart [--dry-run] [--json]homesrvctl cloudflared reload [--dry-run] [--json]homesrvctl validate [--json]homesrvctl doctor <hostname> [--json]
Notes
bootstrapcommands are explicit slices, not a single unattended installer.homesrvctldoes not prompt forsudo; privileged setup steps print or require the commands to run.- After bootstrap, the normal operator should not need root for stack scaffolding, domain ingress changes, Docker Compose stack lifecycle, or
cloudflaredrestart/reload through the scoped policy. domain add,domain repair, anddomain removepreflight local ingress mutation safety before writing DNS.domain status,doctor,validate, andcloudflared config-testdistinguish blocking ingress problems from advisory wildcard-ordering risks.cloudflared reloadis available only when the detected runtime exposes a safe reload command;restartremains the predictable cross-runtime baseline.site initis the narrow static scaffold;app init --template staticis the richer nginx-backed static app baseline.- The Textual TUI is backed by existing JSON command surfaces. It requires an interactive terminal and the same local runtime access as the CLI commands it launches.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file homesrvctl-0.4.0.tar.gz.
File metadata
- Download URL: homesrvctl-0.4.0.tar.gz
- Upload date:
- Size: 151.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc1e0a8aadcfdb391725079e8e073d35dbf37d62cf360772e69e5a5a09588710
|
|
| MD5 |
ae017aa254a37aca243cc030d91a5b74
|
|
| BLAKE2b-256 |
be34a28ea39bd378acf52b23de0f95378fe5f52e229926c7b191bd6d44a43207
|
Provenance
The following attestation bundles were made for homesrvctl-0.4.0.tar.gz:
Publisher:
release.yml on Broda/homesrvctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
homesrvctl-0.4.0.tar.gz -
Subject digest:
bc1e0a8aadcfdb391725079e8e073d35dbf37d62cf360772e69e5a5a09588710 - Sigstore transparency entry: 1375657504
- Sigstore integration time:
-
Permalink:
Broda/homesrvctl@0e6f6732c15734e7536ce24f1289df33dab9e743 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/Broda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0e6f6732c15734e7536ce24f1289df33dab9e743 -
Trigger Event:
push
-
Statement type:
File details
Details for the file homesrvctl-0.4.0-py3-none-any.whl.
File metadata
- Download URL: homesrvctl-0.4.0-py3-none-any.whl
- Upload date:
- Size: 127.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
110137b4a0b5152b440198ddeb5e4c029b23f7eaa6271cd9c5203e042d942860
|
|
| MD5 |
105d9bb150f3a6957bcfa85552812abb
|
|
| BLAKE2b-256 |
777bfa0dde97967be21ef1afa6721d810d5de36916e4bcc8df9b71be9db287df
|
Provenance
The following attestation bundles were made for homesrvctl-0.4.0-py3-none-any.whl:
Publisher:
release.yml on Broda/homesrvctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
homesrvctl-0.4.0-py3-none-any.whl -
Subject digest:
110137b4a0b5152b440198ddeb5e4c029b23f7eaa6271cd9c5203e042d942860 - Sigstore transparency entry: 1375657598
- Sigstore integration time:
-
Permalink:
Broda/homesrvctl@0e6f6732c15734e7536ce24f1289df33dab9e743 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/Broda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0e6f6732c15734e7536ce24f1289df33dab9e743 -
Trigger Event:
push
-
Statement type: