An open API service indexing awesome lists of open source software.

https://github.com/zeslava/dail

Daily jail management for FreeBSD
https://github.com/zeslava/dail

dail freebsd jail

Last synced: 3 months ago
JSON representation

Daily jail management for FreeBSD

Awesome Lists containing this project

README

          

# Dail
Daily jail management for FreeBSD

## Features

- **Familiar workflow:** `create`, `start`, `stop`, `rm`, `run`, `exec`, `build`
- **`.dail` files:** declarative jail builds
- **Presets:** one flag to configure common workloads (`--preset postgres`)
- **Thick & thin jails:** full copy or shared base with per-jail overlay
- **Networking:** inherit, IP alias, or VNET with bridge
- **Port forwarding:** `-p host_port:jail_port` via PF rdr anchors
- **ZFS support:** snapshots, clones, ZFS-backed storage
- **Resource limits:** rctl-based CPU/memory/process limits

## Getting Started

```bash
# 1. Install dail
cargo build --release
doas install -m 755 target/release/dail /usr/local/bin/dail

# 2. Initialize (creates /var/db/dail/, writes default config)
doas dail config init

# 3. Download FreeBSD base
doas dail bootstrap

# 4. Run your first jail
doas dail run myjail

# 5. Open a shell inside
doas dail shell myjail

# 6. Stop and remove
doas dail stop myjail
doas dail rm myjail
```

## Examples

### PostgreSQL

```dockerfile
# postgres.dail
FROM 15.0-RELEASE

PARAM allow.sysvipc=true

RUN pkg install -y postgresql18-server

SERVICE postgresql --no-user

RUN service postgresql oneinitdb

COPY postgresql.conf /var/db/postgres/data18/postgresql.conf
COPY pg_hba.conf /var/db/postgres/data18/pg_hba.conf

EXPOSE 5432
```

```bash
# Build and run
doas dail run postgres.dail --preset postgres

# Check status
doas dail ls

# View logs
doas dail logs postgresql

# Create a user and database for your app (e.g. "zid")
doas -u postgres createuser --pwprompt zid -h 10.100.0.2
doas -u postgres createdb -O zid zid -h 10.100.0.2

# Connect from host
psql -h 10.100.0.2 -U zid -d zid

# Open shell inside jail
doas dail shell postgresql

# Stop and remove
doas dail stop postgresql
doas dail rm postgresql
```

### Custom Rust service (filest)

```dockerfile
# filest.dail
FROM 15.0-RELEASE

SERVICE filest

COPY target/release/filest /usr/local/bin/filest

EXPOSE 8090
```

```bash
# Build the binary on host first
cargo build --release

# Build jail and run
# --uid makes mount ownership match host user
# -e passes namespace config to the service
doas dail run filest.dail --uid 1001 \
--mount /home/user/photos:/data/photos \
-e NS_photos=/data/photos

# Check it's running
doas dail ls
curl http://10.100.0.2:8090/

# View logs
doas dail logs filest

# Rebuild after code changes
cargo build --release
doas dail run filest.dail --rebuild

# Stop
doas dail stop filest
```

## `.dail` File Reference

A `.dail` file describes how to build and run a jail — similar to a Dockerfile.

```dockerfile
# Base FreeBSD release
FROM 15.0-RELEASE

# Install packages
RUN pkg install -y nginx

# Copy config files from build context into the jail
COPY nginx.conf /usr/local/etc/nginx/nginx.conf

# Set environment variables (appended to /etc/profile)
ENV APP_ENV=production

# Jail parameters (FreeBSD jail.conf options)
PARAM allow.raw_sockets=true

# Mount host directories into the jail
MOUNT /home/user/site:/usr/local/www
MOUNT /data:/mnt/data:ro

# Enable a service (creates user/group/dirs, adds to rc.conf)
SERVICE nginx --no-user

# Log file path (used by `dail logs`)
LOG /var/log/nginx/access.log

# Port forwarding (host_port:jail_port)
EXPOSE 8080:80
EXPOSE 443

# Override default startup command
CMD /usr/local/sbin/nginx -g "daemon off;"
```

| Directive | Syntax | Description |
|-----------|--------|-------------|
| `FROM` | `FROM ` | FreeBSD base release |
| `RUN` | `RUN ` | Execute command during build |
| `COPY` | `COPY [--chown=u:g] ` | Copy files into jail (supports globs). Auto-chown to SERVICE user if present |
| `ENV` | `ENV =` | Set environment variable |
| `PARAM` | `PARAM =` | Set jail parameter (see [jail(8)](https://man.freebsd.org/cgi/man.cgi?jail(8))) |
| `MOUNT` | `MOUNT :[:ro]` | Mount host directory (optional `:ro` suffix) |
| `SERVICE` | `SERVICE [--no-user]` | Enable service, create user/group/dirs, set persist |
| `LOG` | `LOG ` | Log file for `dail logs` |
| `EXPOSE` | `EXPOSE [host:][/proto]` | Port forwarding (default tcp, overridden by `-p`) |
| `CMD` | `CMD ` | Startup command (overrides SERVICE default) |

### Common PARAM values

| Parameter | Description |
|-----------|-------------|
| `allow.raw_sockets=true` | Allow ping and raw socket access |
| `allow.sysvipc=true` | Allow SysV IPC (required by PostgreSQL) |
| `allow.mlock=true` | Allow memory locking |
| `allow.chflags=true` | Allow changing file flags |
| `ip4=inherit` | Share host IPv4 stack |
| `ip6=inherit` | Share host IPv6 stack |
| `children.max=5` | Allow nested jails (up to N) |
| `securelevel=0` | Set jail securelevel |

Full list: [jail(8)](https://man.freebsd.org/cgi/man.cgi?jail(8))

## Commands

### Setup

**`dail config init`** — Initialize dail: create directory structure (`/var/db/dail/`), write default config.

```bash
dail config init # directory backend
dail config init --zfs-pool zroot # ZFS backend
```

**`dail bootstrap`** — Download and extract a FreeBSD base system.

```bash
dail bootstrap # download default (15.0-RELEASE)
dail bootstrap 14.2-RELEASE # specific release
dail bootstrap --list # show bootstrapped bases
```

### Jail Lifecycle

**`dail create`** — Create a jail without starting it.

```bash
dail create myjail # thick jail, default base
dail create myjail --type thin --base 14.2-RELEASE
dail create myjail --preset postgres # apply preset
dail create web --vnet --vnet-ip 10.0.0.5/24 --vnet-gateway 10.0.0.1
dail create app --mount /data/app:/app --allow raw_sockets --limit maxproc=256
dail create web -p 8080:80 # port forwarding via PF
dail create app --uid 1001 # service user with specific UID/GID
```

**`dail run`** — Create and start a jail in one step. Same options as `create`, plus `--rm`, `--build`, `--rebuild`.

```bash
dail run myjail # create + start
dail run postgres-jail --preset postgres # with preset
dail run temp --rm # auto-remove on stop
dail run web --vnet --vnet-ip 10.0.0.5/24 --vnet-gateway 10.0.0.1
dail run app --mount /data:/app --preset dev --limit maxproc=512
dail run postgres.dail # build + start, name from filename
dail run postgres.dail --name pg # build with explicit name
dail run postgres.dail --rebuild # rebuild from scratch
dail run https://github.com/user/repo.git --name app # build from git repo
dail run https://github.com/user/repo//jails/web --name web # build from subdirectory
dail run web -p 8080:80 # port forwarding
dail run web -p 8080:80/tcp -p 5432:5432 # multiple ports
dail run app.dail --uid 1001 # service user with specific UID/GID
```

**`dail start`** / **`stop`** / **`restart`** — Manage jail state.

```bash
dail start myjail
dail stop myjail # if --rm was set, jail is auto-removed
dail stop --all # stop all running jails
dail restart myjail
dail restart --all # restart all running jails
```

**`dail rm`** — Remove a jail and its filesystem.

```bash
dail rm myjail # must be stopped
dail rm myjail --force # stop + remove
dail rm --all --force # remove all jails
```

### Inspection

**`dail ls`** — List jails.

```bash
dail ls # all jails (colored status)
dail ls --running # only running
dail ls --format json # JSON output
dail ls -q # names only (for scripting)
```

**`dail inspect`** — Show jail details.

```bash
dail inspect myjail # human-readable
dail inspect myjail --json # raw JSON
```

**`dail config show`** — Display current configuration.

```bash
dail config show
```

### Execution

**`dail exec`** — Run a command inside a jail.

```bash
dail exec myjail ls /etc
dail exec myjail pkg install -y nginx
```

**`dail shell`** — Open an interactive shell.

```bash
dail shell myjail # default /bin/sh
dail shell myjail --shell /bin/csh
```

### Logs

**`dail logs`** — View jail logs. By default reads CMD stdout/stderr (`cmd.log`). If `LOG` is set in the `.dail` file, reads that file from the jail rootfs instead. The log file is auto-created with write permissions at jail start.

```bash
dail logs myjail # CMD output (or LOG file if set in .dail)
dail logs myjail --tail 20 # last 20 lines
dail logs myjail -f # follow (like tail -f)
dail logs myjail --file /var/log/messages # read arbitrary file from jail rootfs
```

### Monitoring

**`dail top`** — Show running processes inside a jail.

```bash
dail top myjail # watch mode (refreshes every 2s)
dail top myjail --once # single snapshot
```

### Build

**`dail build`** — Build a jail from a `.dail` file or git URL.

```bash
dail build pg.dail --name myapp
dail build ./jails/web.dail --name web
dail build https://github.com/user/repo.git --name app # build from git repo
dail build https://github.com/user/repo//jails/web --name web # build from subdirectory
```

### Cache

**`dail cache clean`** — Remove cached pkg packages and repository metadata.

```bash
dail cache clean
```

### Shell Completions

Dail supports dynamic completions — jail names and other values are completed at runtime.

```bash
# Dynamic completions (recommended — live jail name and image completion)
echo 'source <(COMPLETE=zsh dail)' >> ~/.zshrc
echo 'source <(COMPLETE=bash dail)' >> ~/.bashrc
COMPLETE=fish dail > ~/.config/fish/completions/dail.fish

# Static completions (subcommands and flags only, no live names)
dail completions zsh | doas tee /usr/local/share/zsh/site-functions/_dail > /dev/null
dail completions bash | doas tee /usr/local/etc/bash_completion.d/dail > /dev/null
dail completions fish > ~/.config/fish/completions/dail.fish
```

### Snapshots

**`dail snapshot`** — Create a ZFS snapshot (requires ZFS backend).

```bash
dail snapshot myjail # tag: latest
dail snapshot myjail --tag v1.0
```

**`dail clone`** — Clone a jail from a snapshot.

```bash
dail clone myjail myjail-copy # from latest
dail clone myjail:v1.0 myjail-copy # from tagged snapshot
```

### Presets

**`dail preset`** — List available presets.

```bash
dail preset
```

## Presets

Presets apply common jail parameters in one flag:

| Preset | What it does |
|--------|-------------|
| `postgres` | `allow.sysvipc=true` |
| `dev` | `allow.raw_sockets=true`, `allow.sysvipc=true` |

Custom presets: create YAML (or TOML) files in `/var/db/dail/presets/`:

```yaml
# /var/db/dail/presets/myapp.yaml
description: "My custom app"
params:
allow.raw_sockets: "true"
limits:
maxproc: "256"
```

## Network Modes

Dail supports multiple networking configurations:

### Auto IP Allocation (default)

When no network flags are specified, dail automatically allocates an IP from the configured pool:

```bash
dail run myjail # Auto-allocates 10.100.0.X
# Output: IP allocated: 10.100.0.2 on lo0
```

Pool configured in `/usr/local/etc/dail/config.yaml`:

```yaml
ip_pool: 10.100.0.0/24
alias_interface: lo0
```

### Explicit IP Alias

Assign a specific IP address:

```bash
dail create web --ip 10.100.0.50/24
```

**Note:** Dail validates that the IP is not already in use by another jail.

### VNET (Virtual Network)

Full network stack isolation with bridged networking:

```bash
dail create app --vnet --vnet-ip 10.0.0.5/24 --vnet-gateway 10.0.0.1 --vnet-bridge bridge0
```

### Port Forwarding

Forward host ports to jail ports using PF rdr anchors:

```bash
dail run web -p 8080:80 # forward host:8080 → jail:80
dail run web -p 8080:80/tcp -p 5432:5432 # multiple ports, optional proto
```

Requires PF enabled with the dail anchor in `/etc/pf.conf`:

```
rdr-anchor "dail/*"
```

In `.dail` files, use `EXPOSE` to declare default port mappings:

```dockerfile
EXPOSE 5432
EXPOSE 8080:80
```

If `-p` is passed on the CLI, all `EXPOSE` directives are ignored.

### Host Network (inherit)

Share the host's network stack:

```bash
dail create legacy --network inherit
```

### No Network (isolated)

Completely isolated jail with no network access:

```bash
dail create isolated --network none
```

## Configuration

Global config at `/usr/local/etc/dail/config.yaml` (TOML fallback supported):

```yaml
root_dir: /var/db/dail
storage_backend: directory # or "zfs"
default_base: "15.0-RELEASE"
alias_interface: lo0
ip_pool: 10.100.0.0/24
mirror: https://download.freebsd.org/releases

# Optional: for ZFS backend
# zfs_pool: zroot
```

## Requirements

- FreeBSD 13+
- Rust (for building from source)
- ZFS (optional, for snapshot/clone features)

## Building

```bash
cargo build --release
```

## License

BSD-3-Clause