diff --git a/.gitignore b/.gitignore index 2cef73e..9aed13a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ .env .env.* !.env.example + +node_modules +pnpm-lock.yaml \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..50b4381 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# mail-postfixadmin + +Custom PostfixAdmin Docker image and stack for managing Postfix mail server (domains, mailboxes, aliases). The image is based on the official [PostfixAdmin](https://hub.docker.com/_/postfixadmin) image with configuration driven entirely by environment variables. + +## Architecture + +- **Base image:** Official `postfixadmin` image (Docker Hub). +- **Custom layer:** `conf/config.local.php` is copied into the image at `/var/www/html/config.local.php`. This file contains no secrets; it reads all settings from `PFA_*` environment variables (required ones throw at runtime if unset, optional ones have defaults). +- **Runtime:** No bind mounts for config. The container receives configuration only via env vars. The stack expects a MySQL socket bind mount so the app can talk to the database on the host (or same network). +- **Reverse proxy:** The sample compose assumes an external Traefik network and uses labels for routing and TLS; adapt hostnames and network name for your environment. + +## Repository layout + +| Path | Purpose | +|------|--------| +| `conf/config.local.php` | ENV-driven PostfixAdmin config (baked into image). | +| `Dockerfile` | Builds from `postfixadmin`, copies `conf/config.local.php`. | +| `docker-compose.yml` | Sample stack: one service, env vars enumerated so the container receives them. | +| `.env.example` | Documents all `PFA_*` variables (required vs optional, no secrets). | +| `.woodpecker/ci.yml` | CI: install deps, Prettier format check, YAML lint. | +| `.woodpecker/build.yml` | Build: Docker build (linux/amd64), push to registry. | +| `.woodpecker/deploy.yml` | Deploy: trigger stack redeploy via webhook (no clone). | + +Secrets and deployment-specific values are not stored in the repo; they are supplied at deploy time (e.g. stack environment in your orchestration UI). + +## Configuration (PFA_* env vars) + +- **Required (no default):** `PFA_SETUP_PASSWORD`, `PFA_DATABASE_PASSWORD`, `PFA_ADMIN_SMTP_PASSWORD`. The app will exit with a clear error if any of these are missing. +- **Optional:** All other `PFA_*` variables have defaults in `config.local.php`. Override them via environment to match your site (database host, site URL, branding, SMTP, quotas, feature flags, etc.). + +The `docker-compose.yml` **enumerates every variable** under `environment:` so that whatever provides the stack (e.g. Portainer “Environment variables”) can substitute `${PFA_*}` and the container actually receives the values. If you use a different orchestrator, ensure every `PFA_*` var you need is passed into the container environment. + +See `.env.example` for the full list and short descriptions. + +## CI/CD (Woodpecker) + +- **ci:** Runs on pull requests and pushes to `main`. Installs Node deps with pnpm, runs `pnpm format:check` and `pnpm lint` (Prettier + YAML lint). No deployment. +- **build:** Runs on push/tag/manual to `main` (and optionally deployment events), after ci. Builds the Docker image with BuildKit, tags with commit SHA and `latest`, pushes to the configured container registry. Uses repo secrets for registry auth. +- **deploy:** Runs after build; does not clone the repo. Calls a webhook to trigger a stack redeploy so the running stack pulls the new image. Depends on build pipeline only. + +Pipeline order: **ci → build → deploy**. Secrets (registry credentials, webhook URL, notifications) are configured in the Woodpecker repo settings, not in the repo. + +## Local development + +- **Format YAML:** `pnpm format` +- **Check format:** `pnpm format:check` +- **Lint YAML:** `pnpm lint` +- **Build image:** `pnpm docker:build` (tags `latest` for the configured registry repo) +- **Push image:** `pnpm docker:push` (requires prior `docker login` to the registry) + +Use a local `.env` (gitignored) to mirror required/optional vars when testing; do not commit secrets. + +## Deployment (high-level) + +1. Build the image (CI does this on merge to `main`, or run `pnpm docker:build` / `pnpm docker:push` manually). +2. In your container/orchestration UI, create or update a stack using the same `docker-compose.yml` (or equivalent). Ensure the service uses the image built by this repo. +3. Set at least the three required `PFA_*` environment variables in the stack; add any optional overrides for your environment (database host, site URL, branding, etc.). The compose file lists every variable so they are passed into the container. +4. Ensure the stack has access to MySQL (e.g. socket or network) and to the Traefik network (or your reverse proxy) if you use the included labels. Adjust volume mounts and network names to match your host. +5. Redeploy the stack after image or env changes. If you use the deploy pipeline’s webhook, redeploy is triggered automatically after a successful build. + +No deployment-specific hostnames, credentials, or webhook URLs are stored in this repo; configure those in your orchestration and CI secrets.