# Caddy Deployment Helpers

## Files

**Users only run `install_caddy.sh`.** Do not run `lib/*` directly.

- `install_caddy.sh`: prepares Caddy in `binary` or `docker` mode.
- `lib/caddy_helper.sh`: helper template (do not run as installer); deployed by `install_caddy.sh`.
- `lib/shell_config.sh`: internal shell-hook implementation used by `install_caddy.sh`.
- `examples/compose.yaml`: sample only.

Interactive installation asks whether to add a shell hook to the current user's rc file. Non-interactive installation enables it by default unless `--no-configure-shell` is passed. The hook points to the deployed helper, not the repository copy.
At the top of `install_caddy.sh`, set `HELPER_SCRIPT_URL` if you want to publish the helper from a different URL.
Set `SHELL_CONFIG_SCRIPT_URL` if you publish the internal shell configuration library from a different URL.

## Modes

### Binary

- Downloads the latest Caddy release by default from the upstream GitHub releases redirect.
- Writes the binary to `/usr/local/bin/caddy`.
- Writes config to `/etc/caddy/Caddyfile`.
- Writes logs to `/etc/caddy/logs`.
- Uses `/etc/caddy/state` for Caddy state and certificate storage.
- Keeps static files disabled by default.
- Creates `/etc/caddy/site` only when `--enable-static-site` is used.
- Writes `/etc/systemd/system/caddy.service` based on the upstream `caddyserver/dist` unit file.

Generated paths:

- `/etc/caddy`: main config root for Caddy.
- `/etc/caddy/Caddyfile`: generated Caddyfile used by the service.
- `/etc/caddy/.caddy_helper.sh`: deployed helper script used by shell startup hooks.
- `/etc/caddy/.helper.env`: helper settings generated by the installer, currently used for the preferred editor.
- `/etc/caddy/logs`: runtime and access log directory.
- `/etc/caddy/state`: Caddy state directory for certificates, ACME account data, renew state, and local storage.
- `/etc/caddy/site`: optional static site root, created only when `--enable-static-site` is used.
- `/usr/local/bin/caddy`: installed Caddy binary.
- `/etc/systemd/system/caddy.service`: generated systemd unit for binary mode.

### Docker

- Uses `caddy:latest` by default.
- Uses `~/projects/caddy` by default.
- Uses `network_mode: host` because this helper targets gateway-style deployments on Linux hosts.
- Writes `compose.yml` to `~/projects/caddy/compose.yml`.
- Writes the GitOps source config to `~/projects/caddy/Caddyfile`.
- Bind-mounts `./Caddyfile` to `/etc/caddy/Caddyfile:ro`, so the Git-managed source file is the runtime config.
- Stores certificates and runtime data in `caddy_data`, image config state in `caddy_config`, and logs in `caddy_logs`.
- Keeps static files disabled by default.
- Adds the optional `caddy_site` named volume at `/srv` only when `--enable-static-site` is used.

Generated paths under `~/projects/caddy`:

- `Caddyfile`: source Caddyfile stored with the deployment and bind-mounted read-only to `/etc/caddy/Caddyfile`.
- `.caddy_helper.sh`: deployed helper script used by shell startup hooks.
- `.helper.env`: helper settings generated by the installer, currently used for the preferred editor.
- `compose.yml`: generated Docker Compose file for the Caddy container.

Generated Docker volumes:

- `caddy_data`: container `/data`; stores certificates, ACME accounts, renew state, and Caddy-managed runtime data.
- `caddy_config`: container `/config`; stores config state used by the official Docker image.
- `caddy_logs`: container `/var/log/caddy`; stores `runtime.log` and `access.log`.
- `caddy_site`: optional container `/srv` static site volume, created only when `--enable-static-site` is used.

## Install

```bash
cd bitfennec_simple_page/http/linux/caddy
bash install_caddy.sh
```

Run the installer as the login user. Do not prefix the whole command with `sudo`; the installer requests elevated access only when writing system-owned files. This ensures the shell hook is written to the intended user's rc file.

Running without arguments starts an interactive setup wizard. It asks for deployment mode, Docker root or binary version, editor, static site support, and shell integration before showing a confirmation summary.
Pass arguments for non-interactive automation:

```bash
bash install_caddy.sh <binary|docker> [options]
```

| Option                 | Purpose                                            | Default            |
| ---------------------- | -------------------------------------------------- | ------------------ |
| `binary` / `docker`    | Select deployment mode for non-interactive setup   | interactive prompt |
| `--enable-static-site` | Create and wire the optional static site directory | disabled           |
| `--editor <name>`      | Set the editor used by `caddy edit`                | `vim`              |
| `--docker-root <path>` | Override Docker root directory                     | `~/projects/caddy` |
| `--version <x.y.z>`    | Pin a specific Caddy version for binary mode       | latest             |
| `--configure-shell`    | Write the helper hook to the current user's rc      | enabled            |
| `--no-configure-shell` | Skip changes to the current user's rc               | disabled           |

Examples:

```bash
bash install_caddy.sh
bash install_caddy.sh binary
bash install_caddy.sh binary --enable-static-site --editor hx
bash install_caddy.sh docker --docker-root ~/projects/caddy-gateway
bash install_caddy.sh docker --no-configure-shell
```

After installation, open a new shell or run:

```bash
exec $SHELL -l
```

To rewrite only the shell helper hook later, use the same entrypoint from a repository checkout:

```bash
# Binary mode
bash install_caddy.sh configure-shell binary

# Docker mode
bash install_caddy.sh configure-shell docker --docker-root <docker-root>
```

## Commands

Load the wrapper in bash:

```bash
source /etc/caddy/.caddy_helper.sh
```

For Docker mode, source the deployed helper instead:

```bash
source <docker-root>/.caddy_helper.sh
```

The helper now registers completion for both bash and zsh. In zsh, no manual `bashcompinit` setup is required after the updated helper is deployed.
`install_caddy.sh configure-shell` detects the current shell: bash uses `~/.bashrc`, zsh uses `~/.zshrc`, fish uses `~/.config/fish/config.fish`, and other shells use `~/.profile`. In Docker mode, it also refreshes `.helper.env` with the selected Docker root.
In Docker mode, the helper resolves the active deployment from the current directory or its parents when it finds `compose.yml` or `compose.yaml` with `Caddyfile` or `.helper.env`. This lets copied or moved deployment directories work without relying on the original install path.
Use `caddy reload` after changing the Docker source `Caddyfile`; the container reads the bind-mounted source file directly.

### Moving the Docker deployment directory

The generated Compose file bind-mounts `./Caddyfile`, so the runtime config moves with the deployment directory. Certificates, runtime data, and logs stay in Docker volumes when the deployment directory is moved. They do not move with the directory and should be backed up separately.

Move the directory like this:

```bash
cd <old-docker-root>
docker compose stop

mv <old-docker-root> <new-docker-root>

cd <new-docker-root>
bash <(curl -fsSL https://www.mgrsc.top/http/linux/caddy/install_caddy.sh) configure-shell docker --docker-root "$PWD"
exec $SHELL -l
caddy status
caddy up
```

Run the `configure-shell` command after moving the directory because the shell startup hook and `.helper.env` may still contain the old Docker root.

If the final directory name changes, Docker Compose may treat the moved directory as a different project. This can make `docker compose ps` miss the old container or make `docker compose up -d` conflict with the existing `container_name: caddy`. To avoid project name drift after renaming the directory, run Compose with a fixed project name:

```bash
docker compose -p caddy up -d
```

When migrating an older deployment that used `caddy_etc`, recreate the service container after updating `compose.yml`:

```bash
docker compose down
docker compose up -d
```

Do not use `docker compose down -v` unless you intentionally want to delete certificate, config, log, and static-site volumes. The old `caddy_etc` volume is no longer used by new Compose files; remove it manually only after confirming it contains no needed files.

Common commands:

```bash
caddy up
caddy down
caddy restart
caddy reload
caddy status
caddy edit
caddy version
caddy logs runtime
caddy logs runtime -f
caddy logs access
caddy logs access -f
caddy fmt
caddy validate
```

`caddy version` now prints deployment details before the upstream version line, including:

- active mode
- install root and config paths
- log and state directories, bind-mounted config, or Docker named volumes
- helper script and helper env paths
- static site status
- generated files, directories, bind mounts, and Docker named volumes with `present` or `missing` status

## Logs

- `runtime.log`: Caddy runtime events such as startup, reload, ACME certificate issuance, renewal, and internal warnings/errors.
- `access.log`: HTTP request logs such as client IP, method, path, status, and response details.

In Docker mode, both files live in the `caddy_logs` named volume at `/var/log/caddy`; use `caddy logs runtime` or `caddy logs access` instead of reading a host-side `logs` directory. Follow mode uses the running `caddy` service container and does not create one-off Compose containers.

The generated Caddyfile follows Caddy's logging model:

- The global options block configures the default runtime logger and excludes `http.log.access`.
- HTTP access logging is enabled by the site-level `log` directive, not by the global options block.
- A `(site_logs)` snippet writes site access logs to one shared `access.log`; import it in each added site block that should use the shared access log.

## Permissions

- Binary mode needs root or a sudo-capable user because it writes under `/usr/local/bin`, `/etc/caddy`, and `/etc/systemd/system`.
- Docker mode writes deployment files under the selected docker root and uses Docker named volumes for runtime state, so it typically runs as the current user with Docker access.

## Validation

Run `shellcheck` and `shfmt` on modified shell scripts before publishing changes.
