# PostgreSQL 18 Install Plan

Target:

- jail: `db`
- hostname: `db.clawdie.si`
- purpose: local memory database
- package family: PostgreSQL 18

## Initial assumptions

- `db` is a persistent FreeBSD jail
- `db` is a thick jail
- current preferred path uses VNET
- storage is on ZFS through the jail dataset
- service binds locally first
- external API layers are deferred

## Why thick

Use a thick jail for `db`.

Reason:

- database is a persistent service
- upgrades and rollback should be predictable
- host coupling should be minimized
- ZFS snapshots are more valuable when the jail shape is stable

## Network profiles

### Shared

Simple alternative if separate service identity is not required.

Pros:

- simplest bring-up
- fewer moving parts
- enough for host-side Clawdie to talk to PostgreSQL

Cons:

- no separate externally meaningful service identity
- `db.clawdie.si` is then mainly an internal jail hostname

### VNET

Current preferred deployment path.

Pros:

- separate network identity
- cleaner future exposure policy
- easier host firewall segmentation

Cons:

- more setup and debugging
- not necessary to prove PostgreSQL installation

Recommended policy:

- if you want the simplest possible bring-up, use `shared`
- if you want stable long-lived service identity from day one, use `vnet`
- current chosen path for `db`: `vnet`

## Known-good create command

```sh
sudo bastille create -T -B -g 192.168.100.1 db 15.0-RELEASE 192.168.100.2/24 warden0
```

## Expected successful Bastille output

Healthy creation includes lines like:

- `Attempting to create jail: db`
- `Valid IP: 192.168.100.2/24`
- `Valid interface: warden0`
- `Creating a thickjail. This may take a while...`
- `e0a_db`
- `e0b_db`
- `Applying template: default/vnet...`
- `ifconfig_vnet0:  -> inet 192.168.100.2/24`
- `Applying template: default/thick...`
- `Applying template: default/base...`

Non-fatal note:

- `[WARNING]: No value provided for arg: IFCONFIG6`

That warning is expected if IPv6 is not configured in the template path.

Intermediate state after successful create but before final validation:

- `hostname` may still be `db`
- `vnet0` should have `192.168.100.2/24`
- if `netstat -rn` lacks a `default` route, the create path is still wrong

Systemic fix for repeated missing default route:

- include the explicit gateway flag: `-g 192.168.100.1`
- do not treat a manual `route add default 192.168.100.1` as the final fix

## Restore modes

Design deployment to support:

- empty database bring-up
- restore from dump

Supported future restore sources should include:

- plain `.sql`
- PostgreSQL custom dump

## Install order

1. Enter the jail.
2. Install PostgreSQL 18 packages.
3. Enable `allow.sysvipc` for the jail and restart it.
4. Enable PostgreSQL in the jail rc.conf.
5. Initialize the data directory.
6. Start PostgreSQL.
7. Confirm `postgres` is listening on loopback.

Canonical prerequisite before `initdb`:

```sh
sudo bastille config db set allow.sysvipc 1
sudo bastille restart db
```

## Defer until later

- `pgvector`
- PostgREST
- schema creation
- remote network exposure
- replication

## Resource baseline

- minimal: `1G RAM / 10G / 1 vCPU`
- balanced: `2G RAM / 15G / 1 vCPU`

Current default for first install:

- `1G RAM / 10G / 1 vCPU`
