No description
  • Go 92.9%
  • HTML 5.5%
  • CSS 1.6%
Find a file
2026-03-18 21:38:46 +01:00
cmd/hosty more planning docs, fixed hardcoded paths in tests, more ui fixes. 2026-03-18 21:38:46 +01:00
internal more planning docs, fixed hardcoded paths in tests, more ui fixes. 2026-03-18 21:38:46 +01:00
planning more planning docs, fixed hardcoded paths in tests, more ui fixes. 2026-03-18 21:38:46 +01:00
CLAUDE.md initial commit 2026-03-18 15:42:31 +01:00
go.mod initial commit 2026-03-18 15:42:31 +01:00
go.sum initial commit 2026-03-18 15:42:31 +01:00
idea.md initial commit 2026-03-18 15:42:31 +01:00
README.md more planning docs, fixed hardcoded paths in tests, more ui fixes. 2026-03-18 21:38:46 +01:00

hosty

hosty is a self-hosted service management tool. It runs each service inside an Incus container, routes traffic through Caddy, and describes everything about a service — its image, ports, environment, and lifecycle scripts — in a single Basefile.


🏗️ Prerequisites

  • Go 1.24+ — for building the binary inside hosty-dev
  • Incus — hosty-dev must have Incus installed and running
  • Caddy — two instances: one on the host (terminates TLS, proxies the hosty UI), one on hosty-dev (managed automatically by hosty for per-service routing)
  • SQLite — no setup needed; hosty creates the database file on first run

⚙️ Config file

hosty reads a YAML config file on startup. Three fields are required:

domain: example.com
db: /var/lib/hosty/hosty.db
listen: :8090
  • domain — root domain for services (e.g. a service named wiki gets subdomain wiki.example.com)
  • db — path to the SQLite database file (created automatically)
  • listen — address hosty's HTTP server binds to

🔨 Building

hosty must be built inside the hosty-dev Incus VM, where the source is live-mounted at /home/hosty/src:

cd /home/hosty/src
go build -buildvcs=false -o /usr/local/bin/hosty ./cmd/hosty/

🚀 Running hosty

Start the web server:

hosty /etc/hosty.yaml serve

hosty binds to the listen address from the config and serves the management UI. Keep it running in the background (e.g. with nohup or a service manager).


📄 Writing a Basefile

A Basefile is a YAML file that lives in your service's source directory. It tells hosty everything it needs to deploy and run the service.

name: wiki
description: A simple markdown wiki
image: ubuntu:24.04
port: 3000
auth: none
data:
  - data
env:
  DOCS_DIR: /var/lib/hosty/wiki/data
  PORT: "3000"
tasks:
  install: |
    apt-get update -y && apt-get install -y curl
    curl -fsSL https://example.com/wiki-install.sh | sh
  start: |
    wiki --docs /var/lib/hosty/wiki/data --port 3000

Key fields:

Field Description
name Unique service name. Also used as the container name and subdomain prefix.
image Incus image reference (e.g. ubuntu:24.04).
port Port the service listens on inside the container.
auth Authentication mode. none means publicly accessible.
data List of data subdirectories created under /var/lib/hosty/<name>/.
env Environment variables injected into the container.
tasks.install Shell commands run once at install time.
tasks.start Shell commands run at start time (fire-and-forget via nohup).

📦 Installing a service

Point hosty at a directory that contains a Basefile:

hosty /etc/hosty.yaml install /path/to/service

hosty will prompt you to confirm the subdomain (defaulting to <name>.<domain>), then:

  1. Create an Incus container from the specified image
  2. Inject environment variables
  3. Create data directories
  4. Run the install task
  5. Add a Caddy route so the service is immediately reachable
  6. Run the start task in the background

▶️ Start, stop, destroy

After a service is installed, use these commands to manage its lifecycle:

hosty /etc/hosty.yaml start <name>
hosty /etc/hosty.yaml stop <name>
hosty /etc/hosty.yaml destroy <name>
  • start — starts the container, waits for an IP, re-adds the Caddy route, and runs the start task
  • stop — gracefully stops the container and removes the Caddy route
  • destroy — stops and deletes the container, removes the Caddy route, and deletes the DB record

⚠️ destroy does not remove data directories under /var/lib/hosty/<name>/. Clean those up manually when you're sure you no longer need them.


🌐 Caddy setup

hosty uses two Caddy instances:

On the host (e.g. servo) — add two entries to your Caddyfile: one for the hosty management UI and one wildcard entry to forward all service subdomain traffic to hosty-dev's Caddy:

hosty.example.com {
    reverse_proxy <hosty-dev-ip>:8090
}

*.hosty.example.com {
    reverse_proxy <hosty-dev-ip>:8080
}

Replace <hosty-dev-ip> with hosty-dev's IP on your network. Port 8090 should match your hosty listen config. Port 8080 is where hosty-dev's Caddy instance listens for per-service routing.

⚠️ Both entries are required. Without the *.hosty.example.com wildcard, service subdomain requests (e.g. https://marki.hosty.example.com) will not reach hosty-dev's Caddy and will show the wrong page.

On hosty-dev — you don't need to touch this. hosty drives Caddy's admin API (localhost:2019) automatically when services are installed, started, stopped, or destroyed. Per-service routing is fully managed.