Dockerised stack composing a full fmsg setup including: fmsgd, fmsgid and fmsg-webapi
fmsg-docker/
├── docker/
│ ├── fmsgd/
│ │ └── Dockerfile # builds fmsgd from source
│ ├── fmsgid/
│ │ └── Dockerfile # builds fmsgid from source
│ └── fmsg-webapi/
│ └── Dockerfile # builds fmsg-webapi from source
│
├── compose/
│ ├── docker-compose.yml # full fmsg stack
│ └── .env # environment configuration
│
└── README.md
| Service | Description |
|---|---|
postgres |
PostgreSQL database shared by fmsgd, fmsgid and fmsg-webapi |
fmsgid |
fmsg Id HTTP API — manages users and quotas |
fmsgd |
fmsg host — sends and receives fmsg messages |
fmsg-webapi |
fmsg Web API — HTTP interface to the fmsg db |
The compose stack uses Docker named volumes:
| Volume | Mounted at | Used by | Contents |
|---|---|---|---|
postgres_data |
/var/lib/postgresql/data |
postgres | All PostgreSQL databases and WAL |
fmsg_data |
/opt/fmsg/data |
fmsgd, fmsg-webapi | fmsg host data (keys, messages) |
fmsgid_data |
/opt/fmsgid/data |
fmsgid | fmsgid data (addresses CSV) |
letsencrypt |
/etc/letsencrypt |
certbot, fmsgd, fmsg-webapi | Let's Encrypt TLS certificates |
WARNING: These volumes contain sensitive application data including user identities and messages. Restrict access to the Docker host and the volumes directory accordingly.
Ensure you have a backup plan for both volumes. Data loss from a volume being deleted or corrupted is not recoverable without backups. Access to backups should equally restricted - consider encryption needs.
-
Copy the example environment file and edit it:
cp .env.example compose/.envSet all required variables in
compose/.env:FMSG_DOMAIN=example.com CERTBOT_EMAIL=admin@example.com FMSG_API_JWT_SECRET=<secret> FMSGD_WRITER_PGPASSWORD=<strong random password> FMSGID_WRITER_PGPASSWORD=<strong random password> -
On the first run, supply the one-time initialisation passwords as command-line arguments rather than storing them in
.env. From thecompose/directory:PGPASSWORD=<superuser password> \ FMSGD_READER_PGPASSWORD=<reader password> \ FMSGID_READER_PGPASSWORD=<reader password> \ docker compose up -dThese variables are only needed during the first startup when the database volume is empty. Passing them on the command line keeps them out of files on disk.
PGUSERdefaults topostgresif not set. -
On subsequent starts, only the
.envfile is needed:docker compose up -d -
fmsgd will be available on port
4930(or the port set byFMSG_PORTin.env).
End-to-end tests that spin up two full stacks (hairpin.local and example.com) on a shared Docker network and exchange messages between them using fmsg-cli.
Prerequisites: Docker, docker compose, Go 1.24+, curl.
# Run tests (starts stacks fresh)
./test/run-tests.sh
# Run tests against already-running stacks (skips stack teardown, startup, and seeding)
./test/run-tests.sh --no-start
# Tear down stacks & network
./test/run-tests.sh cleanupTests also run on demand via the Integration Test GitHub Actions workflow.
Configure these in compose/.env. Variables marked required have no default and must be set.
| Variable | Required | Default | Description |
|---|---|---|---|
FMSG_DOMAIN |
yes | The domain name for your fmsg host | |
CERTBOT_EMAIL |
yes | Email address for Let's Encrypt certificate registration | |
FMSG_API_JWT_SECRET |
yes | HMAC secret for fmsg-webapi JWT validation | |
FMSG_PORT |
no | 4930 |
Host port fmsgd listens on |
FMSGID_PORT |
no | 8080 |
Internal port for the fmsgid API |
GIN_MODE |
no | release |
Gin framework mode for fmsgid (release or debug) |
FMSG_SKIP_DOMAIN_IP_CHECK |
no | false |
Skip domain-to-IP validation in fmsgd (useful for dev) |
The PostgreSQL instance hosts two separate databases (fmsgd and fmsgid) with dedicated roles per service.
| Variable | Required | Default | Description |
|---|---|---|---|
PGUSER |
no | postgres |
PostgreSQL superuser name (used for first-run init only) |
PGPASSWORD |
init | PostgreSQL superuser password (only needed on first run) | |
FMSGD_WRITER_PGPASSWORD |
yes | Password for fmsgd_writer role (used by fmsgd & webapi) |
|
FMSGD_READER_PGPASSWORD |
init | Password for fmsgd_reader role (only needed on first run) |
|
FMSGID_WRITER_PGPASSWORD |
yes | Password for fmsgid_writer role (used by fmsgid) |
|
FMSGID_READER_PGPASSWORD |
init | Password for fmsgid_reader role (only needed on first run) |
Variables marked init are only required on the first startup when the database is being initialised. They can be passed as command-line environment variables (see Getting Started) to avoid storing them on disk.
On first startup (empty data volume), PostgreSQL runs the scripts in docker/postgres/init/ in order:
| Script | Purpose |
|---|---|
001-init.sh |
Creates roles (with passwords from env) and databases |
002-fmsgd-dd.sql |
Creates tables and other database objects for fmsgd |
002-fmsgid-dd.sql |
Creates tables and other database objects for fmsgid |
999-permissions.sql |
Grants permissions after all objects exist |
WARNING: To re-run initialisation you must remove the
postgres_datavolume. This permanently destroys all data in both thefmsgdandfmsgiddatabases — including user accounts, messages, and any other application state stored in PostgreSQL. Only do this if you intend to start from scratch.docker compose down docker volume rm <project>_postgres_data docker compose up -d # supply init passwords again