summaryrefslogtreecommitdiff
path: root/USER_GUIDE.md
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-08-07 00:03:04 -0500
committerClaude <noreply@anthropic.com>2026-08-07 00:03:04 -0500
commitd1e1c226d9a63432c652d373c039a3ae4430f3a2 (patch)
tree79b72917b757f6807c1beb9872efc2ea694cce6d /USER_GUIDE.md
parentf34ba20fc566ab861179a8ac2fd55eaabbc6a327 (diff)
Guard deploys and config changes against leftover state on retry
- 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.
Diffstat (limited to 'USER_GUIDE.md')
-rw-r--r--USER_GUIDE.md24
1 files changed, 22 insertions, 2 deletions
diff --git a/USER_GUIDE.md b/USER_GUIDE.md
index 04ec92e..fa8449c 100644
--- a/USER_GUIDE.md
+++ b/USER_GUIDE.md
@@ -283,7 +283,26 @@ bar is garbled without a real tty.
# mkdir -p /skiff/repos
```
-#### 3. Nginx
+#### 3. Jail config
+
+FreeBSD doesn't ship an `/etc/jail.conf`, and at boot `service jail
+start` (invoked with no jail named) only creates jails it finds in that
+one file - it never looks inside `jail.conf.d/` on its own. Point it
+there once:
+
+```
+# echo '.include "/etc/jail.conf.d/*.conf";' > /etc/jail.conf
+```
+
+Skip this and everything still *appears* to work: `skiff new-app` starts
+the new jail immediately, and a manual `service jail start <app>` after
+a reboot works too - both read `jail.conf.d/<app>.conf` directly,
+bypassing `/etc/jail.conf` entirely. Only the boot-time, no-name form of
+`service jail start` actually depends on the include line, so the gap
+stays invisible until the host reboots and no app jail comes back up on
+its own - see the [Troubleshooting](#troubleshooting) entry below.
+
+#### 4. Nginx
Add once to `/usr/local/etc/nginx/nginx.conf`, inside the `http` block:
@@ -300,7 +319,7 @@ include /usr/local/etc/nginx/skiff.d/*.conf;
Skiff only ever writes files under `skiff.d/` and reloads - it never
touches `nginx.conf` itself.
-#### 4. Install skiff
+#### 5. Install skiff
Cross-compile from any machine with Go, then copy the binary over:
@@ -405,6 +424,7 @@ Carried over from the project's own README, plus what testing surfaced:
|---|---|---|
| `zfs clone ...: parent does not exist` on `new-app` | `zroot/skiff/apps` was created as a directory, not a dataset | `zfs create -o mountpoint=/skiff/apps zroot/skiff/apps` |
| `Cannot 'start' jail. Set jail_enable to YES...` | `jail_enable` unset | `sysrc jail_enable=YES` |
+| App jails don't come back up after a host reboot, even with `jail_enable=YES` and manual `service jail start <app>` working fine | `/etc/jail.conf` missing or doesn't `.include` `jail.conf.d/*.conf` - boot-time `service jail start` only creates jails it finds in `/etc/jail.conf` itself | `echo '.include "/etc/jail.conf.d/*.conf";' > /etc/jail.conf` (see [Jail config](#3-jail-config)) |
| Deploy always health-check-fails with `connection refused`, even though the app builds fine | Jail's IP was never aliased onto a host interface | `ifconfig <if> alias <ip>/<mask>` (see [Provisioning](#provisioning-a-new-app)) |
| `git worktree add ...: missing but already registered worktree` on redeploy | Stale worktree entry after a rollback deleted a release dir (older skiff binaries only) | `git -C /skiff/repos/<app>.git worktree prune` |
| `bsdinstall jail` spins at 100% CPU forever | Interactive `dialog` waiting on a terminal that isn't there | Kill it, re-run with `nonInteractive=YES` and `BSDINSTALL_DISTSITE` set (see setup section) |