Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# ── Required ──────────────────────────────────────────────
# fmsg domain name this host serves
# - fmsgd will uses TCP 4930 on fmsg.<FMSG_DOMAIN>
# - fmsg-webapi uses HTTPS 443 on fmsgapi.<FMSG_DOMAIN>
FMSG_DOMAIN=example.com
# Email address for Let's Encrypt certificate registration
CERTBOT_EMAIL=
# ── Required ──────────────────────────────────────────────

# fmsg domain name this host serves
# - fmsgd will uses TCP 4930 on fmsg.<FMSG_DOMAIN>
# - fmsg-webapi uses HTTPS 443 on fmsgapi.<FMSG_DOMAIN>
FMSG_DOMAIN=example.com

# Email address for Let's Encrypt certificate registration
CERTBOT_EMAIL=

# Base64-encoded Ed25519 seed or private key used by fmsg-webapi to mint
# short-lived first-party JWTs from API keys. Generate with:
# openssl rand -base64 32
Expand All @@ -16,15 +16,21 @@ FMSG_API_TOKEN_ED25519_PRIVATE_KEY=changeme
# Per-service database passwords (used by application services)
FMSGD_WRITER_PGPASSWORD=changeme
FMSGID_WRITER_PGPASSWORD=changeme

# ── Optional (defaults shown) ────────────────────────────

# FMSG_PORT=4930
FMSGD_READER_PGPASSWORD=changeme
FMSGD_READER_PGPASSWORD=changeme

# ── Optional (defaults shown) ────────────────────────────

# FMSG_PORT=4930
# FMSGID_PORT=8080
# GIN_MODE=release
# FMSG_SKIP_DOMAIN_IP_CHECK=false

# External user JWT login (optional; set all four to enable JWKS auth)

# External identity-provider JWT authentication (optional): configure these
# variables when fmsg-webapi should validate JWTs issued by an external
# identity provider through its JWKS endpoint.
#
# FMSG_JWT_JWKS_URL=https://idp.example.com/.well-known/jwks.json
# FMSG_JWT_ISSUER=https://idp.example.com/
# FMSG_JWT_AUDIENCE=fmsg-web-client
Expand Down
104 changes: 80 additions & 24 deletions QUICKSTART.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Quickstart - Setting up an fmsg host with fmsg-docker

This quickstart gets the docker compose stack from this repository up and running on your server. TLS provisioning is included and an HTTPS API is exposed so you can start sending and receiving fmsg messages for your domain. TCP port 4930 is also exposed for fmsg host-to-host communication.
This quickstart gets the docker compose stack from this repository up and running on your public fmsg server.

To learn more about fmsg, see the documentation repository: [fmsg](https://github.com/markmnl/fmsg).
TLS provisioning is included and an HTTPS API is exposed so you can start sending and receiving fmsg messages for your domain. TCP port 4930 is also exposed for fmsg host-to-host communication.


## Other Docs

| Name | Description |
|--------------------------------------------|--------------------------------------------------------------------|
| [README.md](README.md) | Full README for this code repository. |
| [README_LOCAL_DEV.md](README_LOCAL_DEV.md) | Run the stack locally for development purposes. |

Read the [README.md](https://github.com/markmnl/fmsg-docker) of this repo for more about settings and environment being used in this quickstart.

## Requirements

Expand All @@ -13,17 +20,24 @@ Read the [README.md](https://github.com/markmnl/fmsg-docker) of this repo for mo
1. TCP port `4930` open to the internet (fmsg TLS)
2. TCP port `443` open to the internet (fmsg-webapi HTTPS)
3. TCP port `80` open to the internet (only first start - required for initial Let's Encrypt certificate issuance)
3. Docker and Docker Compose
3. Docker and Docker Compose, or Podman and podman-compose

## Steps

_NOTE_ This quickstart uses `docker compose` throughout. If you are using Podman, replace each occurrence with `podman compose`.

### 0. Server Setup

Clone this repository to the server and make sure docker is running.
```
git clone https://github.com/markmnl/fmsg-docker.git
Make sure Docker is installed and running. Create a dedicated non-root `fmsg` operator account, create its checkout location, and shallow-clone the repository's default branch:

```sh
sudo useradd --create-home --shell /bin/bash fmsg
sudo install -d --owner=fmsg --group=fmsg /opt/fmsg-docker
sudo -u fmsg git clone --depth 1 https://github.com/markmnl/fmsg-docker.git /opt/fmsg-docker
sudo -u fmsg -H bash
```


### 1. Configure DNS

Create A (or AAAA if your public IP is IPv6) DNS records to resolve to your server IP for:
Expand All @@ -35,9 +49,10 @@ _NOTE_ Ensure DNS is kept up-to-date with your server's IP so you can send and r

### 2. Configure FMSG

Copy the example env file:
As the `fmsg` user, configure the checkout in `/opt/fmsg-docker`. Copy the example env file:

```sh
cd /opt/fmsg-docker
cp .env.example compose/.env
```

Expand All @@ -47,7 +62,9 @@ Edit `compose/.env` and set at least:
FMSG_DOMAIN=example.com
CERTBOT_EMAIL=
FMSG_API_TOKEN_ED25519_PRIVATE_KEY=<base64-ed25519-seed>
FMSGD_READER_PGPASSWORD=<strong-password>
FMSGD_WRITER_PGPASSWORD=<strong-password>
FMSGD_READER_PGPASSWORD=<strong-password>
FMSGID_WRITER_PGPASSWORD=<strong-password>
```

Expand All @@ -57,21 +74,24 @@ _NOTE_
* Generate `FMSG_API_TOKEN_ED25519_PRIVATE_KEY` with `openssl rand -base64 32`.
* For all secrets and passwords env vars create your own.

Start the stack for the first time from `compose/` and pass the one-time init passwords on the command line (keep these secret, keep them safe):

(might require sudo)
Exit the fmsg login shell and start the stack for the first time by changing into `/opt/fmsg-docker/compose` and passing the one-time postgres super user password on the command line. (Generate and keep PGPASSWORD yourself, this will only be needed first time running compose up).

```sh
cd compose
PGPASSWORD=<postgres-password> \
FMSGD_READER_PGPASSWORD=<strong-password> \
FMSGID_READER_PGPASSWORD=<strong-password> \
docker compose up -d
exit
cd /opt/fmsg-docker/compose
sudo env PGPASSWORD='<postgres-password>' docker compose up -d
```

First time will take a few minutes to pull docker images and initalise the database. After than check everything started with:

```
sudo docker compose ps
```

If `fmsgd` is running and port `4930` is reachable on `fmsg.<your domain>`, the host is up.

On first start, certbot will request Let's Encrypt TLS certificates for `fmsg.<your-domain>` and `fmsgapi.<your-domain>`. If certificate issuance fails (e.g. the domains do not resolve to the server or port 80 is blocked), the stack will not start. Certificates are persisted in a Docker volume and reused on subsequent starts. Once certificates are issued port 80 is no longer needed until certificates need to be renewed - usually 90 days.
On first start, certbot will request Let's Encrypt TLS certificates for `fmsg.<your-domain>` and `fmsgapi.<your-domain>`. If certificate issuance fails (e.g. the domains do not resolve to the server or port 80 is blocked by firewall, or already in use), the stack will not start. Certificates are persisted in a Docker volume and reused on subsequent starts. Once certificates are issued port 80 is no longer needed until certificates need to be renewed - usually 90 days.


## Next Steps
Expand All @@ -88,24 +108,60 @@ address,display_name,accepting_new,limit_recv_size_total,limit_recv_size_per_msg
You can copy it into the volume with (file changes will sync automatically):

```sh
docker compose cp addresses.csv fmsgid:/opt/fmsgid/data/addresses.csv
sudo docker compose cp addresses.csv fmsgid:/opt/fmsgid/data/addresses.csv
```

### Connect a Client

Create or rotate an API key with the fmsg-webapi operator command, then use it with [fmsg-cli](https://github.com/markmnl/fmsg-cli):
Create an API key for a user, then use it with [fmsg-cli](https://github.com/markmnl/fmsg-cli) or access the [fmsg-webapi](https://github.com/markmnl/fmsg-webapi) API directly at `https://fmsgapi.<your-domain>`.

To create an API key for `@alice@example.com`:

```sh
docker compose exec fmsg-webapi /opt/fmsg-webapi/fmsg-webapi api-key create-delegation \
sudo docker compose exec fmsg-webapi /opt/fmsg-webapi/fmsg-webapi api-key create-delegation \
-owner @alice@example.com \
-agent cli \
-addr @alice@example.com \
-cidr 203.0.113.0/24 \
-expires 2026-12-31T00:00:00Z
-cidr 0.0.0.0/0,::/0 \
-expires 2027-12-31T00:00:00Z

```

* The command prints the plaintext API key only once. Store it securely.
* `owner` and `addr` are the same, so the key authenticates as `@alice@example.com` in the above example.
* CIDR values: `-cidr 0.0.0.0/0,::/0` permit connections from any IPv4 or IPv6 address, restrict per your requirements.

Then use it from fmsg-cli:

```sh
# save this export line to your ~/.bash_profile for future use
export FMSG_API_URL=https://fmsgapi.<your-domain>

fmsg login <fmsg-key>

FMSG_API_URL=https://fmsgapi.example.com \
FMSG_API_KEY=fmsgk_<key_id>_<secret> \
fmsg list
fmsg send @recipient@example.com "Hello, world!"
fmsg send @recipient@example.com ./message.txt
echo "Hello via stdin" | fmsg send @recipient@example.com -
```


To use the API directly instead of fmsg-cli (which uses the API under the hood), exchange the API key for a short-lived JWT:

```sh
export FMSG_API_URL=https://fmsgapi.<your-domain>
export FMSG_API_KEY=fmsgk_<key_id>_<secret>

curl --fail --silent --show-error \
-X POST \
-H "Authorization: Bearer $FMSG_API_KEY" \
"$FMSG_API_URL/fmsg/token"
```

The API key plaintext is printed once when created or rotated. Store it securely and pass it to automated clients through `FMSG_API_KEY`.
The response contains an `access_token`. Send it as a Bearer token with API requests:

```sh
curl --fail --silent --show-error \
-H "Authorization: Bearer <access_token>" \
"$FMSG_API_URL/fmsg"
```
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@

Dockerised stack composing a full fmsg setup including: [fmsgd](https://github.com/markmnl/fmsgd), [fmsgid](https://github.com/markmnl/fmsgid) and [fmsg-webapi](https://github.com/markmnl/fmsg-webapi)

Navigate to [QUICKSTART.md](QUICKSTART.md)

## Other Docs

| Name | Description |
|--------------------------------------------|--------------------------------------------------------------------|
| [QUICKSTART.md](QUICKSTART.md) | Get a production stack up and running on your server in minutes. |
| [README_LOCAL_DEV.md](README_LOCAL_DEV.md) | Run the stack locally for development purposes. |


<div align="center">
<picture>
Expand Down
Loading
Loading