summaryrefslogtreecommitdiff
path: root/USER_GUIDE.md
AgeCommit message (Collapse)Author
2026-09-02Document jail networking on a single public IPClaude
The --ip same-subnet rule from earlier is necessary but not sufficient once a host only has one public address: jails shouldn't get public IPs at all (only nginx needs one), but a private range aliased onto the same interface needs its own outbound NAT rule for jail builds to reach the internet - nothing upstream translates it the way a NAT'd virtual network (like the dev VM) does for free. Skipping it fails the same silent way as the out-of-subnet case: packets leave the jail, nothing answers. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02Rename the default base snapshot from "ready" to "default"Claude
"ready" read as a status word rather than a label for what's actually a mutable pointer to "the current recommended base image," re-tagged as it evolves - the exact operation we did twice this session. "default" names that role directly: it's the value --base-snapshot falls back to, nothing more claimed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02Use the go meta-port instead of a hand-rolled go/gofmt symlinkClaude
FreeBSD's lang/go is a real meta-port (installs as package name "go") that depends on whichever goNNN is current and installs the go/gofmt symlinks itself, tracked and upgradeable - `pkg install go` replaces both the go125 install and the manual `ln -sf` steps in one command. Verified against a real base image and rebuild: same resulting symlinks, now pkg-owned instead of orphaned files pkg doesn't know about. Docs updated to check for an unversioned meta-port first, falling back to a manual symlink only when a toolchain doesn't have one. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02Drop unused --old flag from skiff deployClaude
Its only caller was the post-receive hook skiff itself generates, so "hook parity" meant matching a convention we invented and fully control - there's no external contract keeping it around. deploy.Run never read it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02Add domain and TLS management via skiff domains add/remove/listClaude
Replaces the single server_name string in meta.json with a domain list (one primary, others redirect to it) and TLSDomains tracking what the app's certificate actually covers. Certs are issued/expanded via certbot certonly (webroot, never the --nginx plugin, since Skiff owns and regenerates skiff.d/*.conf itself) as one SAN cert per app, matching how a real multi-domain vhost is normally issued. Domain/TLS changes never touch the jail - no restart, no health check - since they only affect nginx and the certificate. `add` is safe to retry if DNS isn't ready yet; `remove` never calls certbot at all, so it can't fail on an ACME/network problem. Also updates README/USER_GUIDE for the new command surface, one-time TLS host setup (certbot register, renewal cron, reload hook), the --ip same-subnet requirement for jails to reach the network at build time, and the actual base-image provisioning sequence (pkg needs an explicit bootstrap after bsdinstall; versioned port names like go125 need a default symlink) - all found and fixed live while getting this working end-to-end on a real FreeBSD VM. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25Split per-app dataset into OS/data layers, add skiff rebuildMike Wild
Each app now gets two ZFS datasets - a disposable OS layer (zroot/skiff/appbase/<app>) cloned from base, and a persistent data layer (zroot/skiff/appdata/<app>) holding releases/current/env/ meta.json/data.db. `skiff rebuild --app|--all` discards and reclones the OS layer to pick up an OS/toolchain/config-template upgrade, guarded by the same snapshot-and-rollback safety net as deploy and config changes; the data layer is never touched. Also fixes stale docs (builds already run via jexec inside the jail, not on the host; --iface already auto-aliases the jail's IP, so the manual ifconfig step and its troubleshooting entry are gone) found while updating the same sections for this feature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07Guard deploys and config changes against leftover state on retryClaude
- Extract deploy.Run's snapshot -> apply -> restart -> health-check -> rollback-on-failure sequence into deploy.GuardedApply, shared with cmd/skiff's applyConfigChange, which duplicated it verbatim. - Clean up the worktree and snapshot a deploy creates when it fails before cutover (e.g. a failing release-phase migration), so retrying the same sha no longer needs manual cleanup. - Make checkout and snapshotting idempotent for a same-sha retry after a cutover that later got rolled back on a failed health check, where the release dir and snapshot are deliberately left behind by design. - Document the actual cause of a jail not surviving a host reboot: FreeBSD ships no /etc/jail.conf, so boot-time `service jail start` finds nothing to start regardless of jail.conf.d - only name-targeted starts read jail.conf.d directly, which is why manual starts worked.
2026-08-06Add skiff config set/unset/list, backed by /app/env in the app's datasetClaude
Config vars are plain env vars, injected into both the running app (via rc.d) and the release phase, and versioned on the same ZFS snapshot timeline as deploys - a bad config change gets the same automatic snapshot/restart/health-check/rollback guarantee a bad deploy already gets. Extracts deploy.go's health check into internal/health so both paths share it. Verified end-to-end against a FreeBSD VM: config set/unset, automatic rollback on a health-check failure, and explicit `skiff rollback` all correctly carry the env file along with the rest of the dataset.
2026-08-05Initial commit of skiff scaffoldingClaude