Repository navigation
Appliance Image
packer/ bakes the Compose stack into a VM image so a ReportMate host can be
deployed as an appliance rather than assembled by hand. The output is the same
three containers; the image just ships Docker, the project files, and a systemd
unit that starts them.
packer/reportmate.pkr.hcl defines one qemu source producing a qcow2 disk.
| Setting | Value |
|---|---|
| Base image |
https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img (iso_url variable) |
| Checksum | none |
| Disk | 20G, qcow2 |
| Accelerator | kvm |
| SSH user / password |
ubuntu / ubuntu
|
| Output | output-reportmate/reportmate-appliance.qcow2 |
| Mode | headless |
Two variables are exposed: reportmate_tag (default latest), passed to the
provisioning script as REPORTMATE_TAG, and iso_url. The SSH timeout is
20m, and the build shuts the VM down with sudo shutdown -P now.
The build copies the whole repo to /tmp/reportmate, then runs
packer/setup.sh.
Requires Packer and a working KVM host.
packer init packer/reportmate.pkr.hcl
packer build packer/reportmate.pkr.hcl
reportmate_tag reaches setup.sh as the REPORTMATE_TAG environment
variable, but neither setup.sh nor first-boot.sh writes it into .env, so
the appliance runs latest unless the .env or docker-compose.yml you ship
pins the image tags. See Upgrading for the tags each image carries.
- Installs
ca-certificates,curl, andgnupg. - Adds Docker's apt keyring and repository for the running Ubuntu release.
- Installs
docker-ce,docker-ce-cli,containerd.io, anddocker-compose-plugin. - Copies the staged repo from
/tmp/reportmateto/opt/reportmateand deletes/opt/reportmate/packer. - Writes
/opt/reportmate/first-boot.shand makes it executable. - Writes
/etc/systemd/system/reportmate.serviceand enables it.
The script runs with set -euo pipefail, so any failed step fails the build.
reportmate.service is a Type=simple unit that requires and starts after
docker.service and network-online.target, works from /opt/reportmate,
runs first-boot.sh, and restarts on failure.
first-boot.sh is idempotent by way of one check: if /opt/reportmate/.env
does not exist, it copies .env.example and replaces the placeholder strings
with openssl rand -hex 24 values — one value for the DB password, and one
value substituted globally for every occurrence of
change-me-to-a-long-random-string. It then execs docker compose up.
Two consequences worth knowing:
-
The three application secrets end up identical. The
sed -i ... /greplacesAPI_INTERNAL_SECRET,REPORTMATE_PASSPHRASE, andNEXTAUTH_SECRETwith the same generated string. That is functional but means one leaked value is three leaked values. Supply your own.envif you care. -
Supplying your own
.envwins. Drop a complete.envinto/opt/reportmate/before first boot (cloud-init, a mounted config drive, or a snapshot) and the generation step is skipped entirely.
To read the secrets that were generated, cat /opt/reportmate/.env on the
booted appliance.
Two things about the build are fine for a local qcow2 and wrong for anything you hand to someone else.
The qemu source authenticates to the build VM with the cloud image's
ubuntu / ubuntu credentials. Nothing in setup.sh changes or disables that
account, so whatever the base image does with those credentials is what your
appliance does. Harden the account, or inject an SSH key, before distributing
an image.
The file provisioner copies ${path.root}/.. — the entire working tree — into
the image. .env is gitignored, but if one exists in your checkout it is
copied to /opt/reportmate/.env and becomes part of the image, secrets and
all. Build from a clean clone.
The template ships only the qemu source. The README notes that an
amazon-ebs or azure-arm source can be added to the same template and reuse
packer/setup.sh unchanged. That is a supported shape, not something the repo
currently contains — you write the source block.
.github/workflows/ci.yml validates the appliance definition on push, pull
request, and manual dispatch. It copies .env.example to .env and runs
docker compose config --quiet, runs packer fmt -check -diff (report-only,
does not fail the build), packer init plus packer validate, and
shellcheck --severity=error packer/setup.sh.
CI does not build the qcow2, does not start the stack, and does not build or publish any container image — this repo consumes the GHCR images rather than producing them.
Deployment tooling MIT licensed; application images licensed separately (server AGPL-3.0, clients MIT) — reportmate.app