<feed xmlns='http://www.w3.org/2005/Atom'>
<title>skiff.git/internal/layout/layout.go, branch master</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://git.mikeanthonywild.com/skiff.git/atom?h=master</id>
<link rel='self' href='https://git.mikeanthonywild.com/skiff.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/'/>
<updated>2026-09-03T02:00:08Z</updated>
<entry>
<title>Add domain and TLS management via skiff domains add/remove/list</title>
<updated>2026-09-03T02:00:08Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-09-03T02:00:08Z</published>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/commit/?id=6040eff2d2b4618f19d4615d246ea6b0704acdf8'/>
<id>urn:sha1:6040eff2d2b4618f19d4615d246ea6b0704acdf8</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Split per-app dataset into OS/data layers, add skiff rebuild</title>
<updated>2026-08-26T04:04:10Z</updated>
<author>
<name>Mike Wild</name>
<email>mike@mikeanthonywild.com</email>
</author>
<published>2026-08-26T04:04:10Z</published>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/commit/?id=025a365a23f5ed2b3df4df71cbff9689575968d9'/>
<id>urn:sha1:025a365a23f5ed2b3df4df71cbff9689575968d9</id>
<content type='text'>
Each app now gets two ZFS datasets - a disposable OS layer
(zroot/skiff/appbase/&lt;app&gt;) cloned from base, and a persistent data
layer (zroot/skiff/appdata/&lt;app&gt;) 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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>new-app: configure jail mail relay and persist the jail's network alias</title>
<updated>2026-08-26T02:23:04Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-08-26T02:23:04Z</published>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/commit/?id=2a9ca0577ecdbee8b5a4bc8886c112dbc4260eab'/>
<id>urn:sha1:2a9ca0577ecdbee8b5a4bc8886c112dbc4260eab</id>
<content type='text'>
Two provisioning gaps in new-app:

- The jail's dma.conf inherited the base image's shared SMARTHOST/
  PORT/AUTHPATH, but never got a per-app MAILNAME - without one, dma
  can misroute mail for recipients on the jail's own apex domain as
  local delivery. EnableMail appends a MAILNAME of &lt;app&gt;.skiff.local,
  which can't collide with any real domain an app sends to or from.

- A classic jail's ip4.addr is only a bind restriction, not a route,
  until something aliases it onto a host interface. jail.conf.tmpl
  never set jail(8)'s own `interface` parameter, so nothing ever
  created that alias - confirmed on skiff-freebsd, where the address
  had twice been made to work via an ad hoc `ifconfig alias` that
  didn't survive a reboot. Setting `interface` lets jail(8) manage
  the alias itself, including on every boot.
</content>
</entry>
<entry>
<title>Add per-app flock locking around deploy, config change, rollback, new-app</title>
<updated>2026-08-08T00:02:40Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-08-08T00:02:40Z</published>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/commit/?id=acde3827f60bc90738429fa490a36a1856a93283'/>
<id>urn:sha1:acde3827f60bc90738429fa490a36a1856a93283</id>
<content type='text'>
Nothing previously serialized these against each other, so concurrent
invocations for the same app (a manual config change racing an
in-flight deploy, a double git push, a rollback mid-deploy) could
interleave snapshot/apply/restart/rollback sequences against the same
dataset and jail. The lock file lives under a new LocksDir, outside
any per-app ZFS dataset, since those datasets get rolled back on a
failed health check or a manual rollback.
</content>
</entry>
<entry>
<title>Add skiff config set/unset/list, backed by /app/env in the app's dataset</title>
<updated>2026-08-07T04:22:03Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-08-07T04:22:03Z</published>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/commit/?id=f34ba20fc566ab861179a8ac2fd55eaabbc6a327'/>
<id>urn:sha1:f34ba20fc566ab861179a8ac2fd55eaabbc6a327</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>Simplify: centralize paths in layout, dedup zfs snapshot refs, remove dead code</title>
<updated>2026-08-06T04:22:25Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-08-06T04:22:25Z</published>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/commit/?id=fc0c6951d7ac36dd8f30ace929991197dc99ae54'/>
<id>urn:sha1:fc0c6951d7ac36dd8f30ace929991197dc99ae54</id>
<content type='text'>
- Add layout.Config methods (ReleasesDir, PostReceiveHookPath, RCScriptPath,
  RCConfPath) so main.go and jailmgr no longer hand-build paths that layout
  already owns.
- Extract zfsutil.snapRef to replace three inline dataset@tag Sprintfs.
- Remove seven unused exported functions (zfsutil.Exists, jailmgr.Stop,
  sh.RunWithStdinFile, and four dead layout.Config path methods) and their
  now-unused imports.
</content>
</entry>
<entry>
<title>Initial commit of skiff scaffolding</title>
<updated>2026-08-06T04:14:29Z</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-08-06T04:14:29Z</published>
<link rel='alternate' type='text/html' href='https://git.mikeanthonywild.com/skiff.git/commit/?id=9f7c9f2f31acd7bc544dd988af1c8c2fe63ec504'/>
<id>urn:sha1:9f7c9f2f31acd7bc544dd988af1c8c2fe63ec504</id>
<content type='text'>
</content>
</entry>
</feed>
