Metadata-Version: 2.4
Name: traefik-control-plane
Version: 0.1.0
Summary: Database-backed control plane and utilities for Traefik
License-Expression: MIT
Project-URL: Homepage, https://codeberg.org/maieretal/traefik_db_auto_config
Project-URL: Repository, https://codeberg.org/maieretal/traefik_db_auto_config
Project-URL: Issues, https://codeberg.org/maieretal/traefik_db_auto_config/issues
Keywords: traefik,postgres,reverse-proxy,control-plane
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: Proxy Servers
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: psycopg[binary]>=3.2
Requires-Dist: PyYAML>=6.0
Dynamic: license-file

# Default Locations

The default layout separates:

- app files under an install prefix such as `/opt/traefik-control-plane/app`
- control-plane config under `/etc/traefik-control-plane`
- runtime-generated data under `/var/lib/traefik-control-plane`

Default installed paths:

- `/opt/traefik-control-plane/app`
- `/etc/traefik-control-plane/control-plane.env`
- `/etc/traefik-control-plane/control-plane.env.example`
- `/etc/traefik-control-plane/dynamic/`
- `/var/lib/traefik-control-plane/dynamic/dynamic_conf.generated.yml`

External input expected from your Traefik deployment:

- `/etc/traefik/static_conf.yml` or another path you set in `TRAEFIK_STATIC_CONFIG_PATH`

## Python Package

This project can be installed directly as a Python package with `pip` or `uv`.

Install from a local checkout:

```bash
uv tool install /path/to/traefik_dynamic_db_delivery
```

or:

```bash
python -m pip install /path/to/traefik_dynamic_db_delivery
```

Install from Git:

```bash
uv tool install git+https://codeberg.org/maieretal/traefik_db_auto_config.git
```

Installed commands:

- `traefik-control-plane`
- `traefik-create-db-schema`
- `traefik-db-restore`
- `traefik-manage`

The package entry points expect the same environment variables as the systemd and Nix installs.

## Install

Default install:

```bash
sudo ./scripts/install.sh
```

Install with explicit directories:

```bash
sudo ./scripts/install.sh \
  --install-root /opt/traefik-control-plane/app \
  --config-dir /etc/traefik-control-plane \
  --runtime-dir /var/lib/traefik-control-plane
```

If you want the optional web UI rebuilt during install:

```bash
sudo ./scripts/install.sh --with-webui
```

The installer:

- builds the optional UI when requested
- installs the Python package into a dedicated venv under the install prefix
- writes launcher scripts into `<install-root>/bin`
- installs systemd units that point at the installed app
- creates the control-plane env file if it does not exist yet
- leaves `<config-dir>/dynamic/*.yml` user-managed and does not seed domain-specific snippets
- does not install or run Traefik

## Runtime Layout

- App launchers:
  - `<install-root>/bin/create-db-schema`
  - `<install-root>/bin/db-restore`
  - `<install-root>/bin/run-control-plane`
  - `<install-root>/bin/run-control-plane-ui`
- User config:
  - `<config-dir>/control-plane.env`
  - `<config-dir>/control-plane.env.example`
  - `<config-dir>/dynamic/*.yml`
- Runtime data:
  - `<runtime-dir>/dynamic/dynamic_conf.generated.yml`

The control plane copies user-managed dynamic snippets from `<config-dir>/dynamic/` into `<runtime-dir>/dynamic/` and renders the generated file there. Your separately managed Traefik instance should watch the runtime directory, not the repository checkout.

## Containers

This repo now includes:

- `Dockerfile` for a control-plane image
- `docker-compose.yml` for running the control plane against an external Postgres database
- `systemd/traefik-control-plane.container` for Podman Quadlet

Both container setups keep the same external contract as the host install:

- mount user config at `/etc/traefik-control-plane`
- mount runtime output at `/var/lib/traefik-control-plane`
- mount Traefik's static config at `/etc/traefik/static_conf.yml`
- provide database settings through `.env` for Compose or `/etc/traefik-control-plane/control-plane.env` for Quadlet
- run in headless sync mode by default

Compose defaults to repo-local bind mounts:

- `./container-data/config`
- `./container-data/runtime`
- `./traefik_conf/static_conf.yml`

Build and run with Compose:

```bash
cp .env.example .env
docker compose up --build -d
```

If you want the optional HTTP API or UI instead of headless mode, remove `--headless` from `docker-compose.yml` or `systemd/traefik-control-plane.container` and publish port `8000`.

Build for Quadlet:

```bash
podman build -t localhost/traefik-control-plane:latest .
```

Then install the unit file under your Quadlet directory, for example:

```bash
sudo install -D -m 0644 systemd/traefik-control-plane.container /etc/containers/systemd/traefik-control-plane.container
sudo systemctl daemon-reload
sudo systemctl enable --now traefik-control-plane.service
```

If you want a rootless Quadlet deployment instead, change the volume and env-file paths in `systemd/traefik-control-plane.container` away from `/etc` and `/var/lib` to paths your user owns.

## Registry Publishing

GitHub publishing is automated:

- [`container.yml`](https://codeberg.org/maieretal/traefik_db_auto_config/src/branch/main/.github/workflows/container.yml) publishes to `ghcr.io/<owner>/<repo>` on pushes to `main` or `master` and on tags matching `v*`

Gitea publishing is local and explicit:

- [`push-gitea-image.sh`](https://codeberg.org/maieretal/traefik_db_auto_config/src/branch/main/scripts/push-gitea-image.sh) builds locally and pushes to `192.168.178.199/denis/traefik-control-plane`

GitHub Actions uses the built-in `GITHUB_TOKEN` with `packages: write`.

For local Gitea pushes:

```bash
export GITEA_REGISTRY_USERNAME='your-user'
export GITEA_REGISTRY_PASSWORD='your-token-or-password'
./scripts/push-gitea-image.sh
```

To push a specific version tag instead of the current commit SHA:

```bash
./scripts/push-gitea-image.sh v1.0.0
```

## systemd

Installed unit files:

- `traefik-control-plane.service`
- `traefik-control-plane-ui.service`

They read environment from:

```text
/etc/traefik-control-plane/control-plane.env
```

Adjust that path by passing a different `--config-dir` during install.

The installer writes these path variables into that env file:

```text
TRAEFIK_CONTROL_PLANE_CONFIG_DIR=/etc/traefik-control-plane
TRAEFIK_RUNTIME_CONFIG_DIR=/var/lib/traefik-control-plane
TRAEFIK_STATIC_CONFIG_PATH=/etc/traefik/static_conf.yml
```

`TRAEFIK_STATIC_CONFIG_PATH` is only a pointer to an externally managed Traefik static config file. This repository does not create or supervise the Traefik runtime.

## Nix

This repo can be deployed with plain Nix or NixOS modules. Flakes are optional.

Build the package with classic Nix:

```bash
nix-build
```

Enter a dev shell with classic Nix:

```bash
nix-shell
```

You can still use the flake outputs if you want:

```bash
nix build .#default
```

Run the built binary:

```bash
result/bin/traefik-control-plane --headless
```

Plain Nix entry points:

- `package.nix`: package definition
- `default.nix`: `nix-build` target
- `shell.nix`: `nix-shell` development environment
- `nix/module.nix`: NixOS module importable by path

Optional flake exports:

- `packages.default`: Python package with the built-in UI assets already included
- `apps.default`: runs `traefik-control-plane`
- `nixosModules.default`: declarative NixOS service module
- `devShells.default`: basic Python/Node/Nix development shell

### NixOS Module

Import the module by path and configure the service declaratively. Keep secrets such as `TRAEFIK_DB_URL` in an external env file instead of embedding them in the Nix store.

```nix
{ config, pkgs, ... }:
{
  imports = [
    /path/to/traefik_dynamic_db_delivery/nix/module.nix
  ];

  services.traefik-control-plane = {
    enable = true;
    headless = true;
    staticConfigPath = "/etc/traefik/static_conf.yml";
    environmentFile = "/run/secrets/traefik-control-plane.env";
    settings = {
      TRAEFIK_API_URL = "http://127.0.0.1:8080";
    };
  };
}
```

Module defaults:

- config snippets: `/var/lib/traefik-control-plane/config/dynamic`
- runtime output: `/var/lib/traefik-control-plane/runtime/dynamic`
- service user/group: `traefik-control-plane`

Important notes:

- `staticConfigPath` must point to your separately managed Traefik static config.
- Put secrets in `environmentFile`, not `settings`.
- If you want the HTTP API or UI, set `headless = false`; set `enableUI = true` to serve the frontend.

## More Detail

- Control-plane delivery service and optional UI: [`control_plane/README.md`](https://codeberg.org/maieretal/traefik_db_auto_config/src/branch/main/control_plane/README.md)
- Traefik config and schema helpers: [`traefik_conf/README.md`](https://codeberg.org/maieretal/traefik_db_auto_config/src/branch/main/traefik_conf/README.md)

## License

This repository is licensed under the MIT License. See [`LICENSE`](https://codeberg.org/maieretal/traefik_db_auto_config/src/branch/main/LICENSE).
