Serve the whole stack under one host name
The stack asked for four public names - one each for PostgreSQL, the S3 API, the MinIO console and pgAdmin - and Caddy refuses to start if two of them are the same, so a server with a single name could not run it. DATA_DOMAIN replaces the four. The services share its one certificate, since a certificate is for a name and not a port, and are told apart by port: 443 S3 API, path-style, at the root of the host 5432 PostgreSQL, TLS terminated by the Layer 4 listener 9443 MinIO console 5443 pgAdmin The S3 API keeps the standard port because MinIO serves buckets from the root of its host and other systems sign requests against it. The console's public port is carried in MINIO_BROWSER_REDIRECT_URL, or MinIO sends the browser back to the S3 API's address. The console and pgAdmin host ports are configurable (CONSOLE_PUBLIC_PORT, PGADMIN_PUBLIC_PORT). An .env from the old layout fails at start with a message naming DATA_DOMAIN; the README says how to move. Data volumes are untouched. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
09d1871a4b
commit
91a0a5d785
17
.env.example
17
.env.example
|
|
@ -1,15 +1,20 @@
|
|||
# All four names must resolve publicly to this server before the first start.
|
||||
POSTGRES_DOMAIN=postgres.example.com
|
||||
MINIO_API_DOMAIN=s3.example.com
|
||||
MINIO_CONSOLE_DOMAIN=minio.example.com
|
||||
PGADMIN_DOMAIN=pgadmin.example.com
|
||||
# One public name for the whole stack. It must resolve publicly to this server before the first
|
||||
# start: Caddy obtains the certificate for it, and every service below uses that one certificate.
|
||||
DATA_DOMAIN=data.example.com
|
||||
TLS_CONTACT=admin@example.com
|
||||
|
||||
# Caddy is the only public entry point. Change the port only if clients also use it.
|
||||
# Caddy is the only public entry point. Change a port only if clients also use it.
|
||||
# HTTPS_PUBLIC_PORT S3 API https://<DATA_DOMAIN>
|
||||
# POSTGRES_PUBLIC_PORT PostgreSQL <DATA_DOMAIN>:5432
|
||||
# CONSOLE_PUBLIC_PORT MinIO console https://<DATA_DOMAIN>:9443
|
||||
# PGADMIN_PUBLIC_PORT pgAdmin https://<DATA_DOMAIN>:5443
|
||||
# HTTP (80) answers certificate challenges and redirects.
|
||||
PUBLIC_BIND_ADDRESS=0.0.0.0
|
||||
HTTP_PUBLIC_PORT=80
|
||||
HTTPS_PUBLIC_PORT=443
|
||||
POSTGRES_PUBLIC_PORT=5432
|
||||
CONSOLE_PUBLIC_PORT=9443
|
||||
PGADMIN_PUBLIC_PORT=5443
|
||||
|
||||
POSTGRES_DB=humainflow
|
||||
POSTGRES_USER=humainflow
|
||||
|
|
|
|||
36
Caddyfile
36
Caddyfile
|
|
@ -17,19 +17,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
# Besides providing a useful status response, this site block tells Caddy to
|
||||
# obtain and renew the certificate used by the Layer 4 PostgreSQL listener.
|
||||
{$POSTGRES_DOMAIN} {
|
||||
respond "PostgreSQL is available on port 5432 with TLS required.\n" 200
|
||||
|
||||
log {
|
||||
output stdout
|
||||
format json
|
||||
}
|
||||
}
|
||||
|
||||
# S3 API. Keep this on its own hostname: S3 request signatures include the host.
|
||||
{$MINIO_API_DOMAIN} {
|
||||
# One host name for everything. Each service has its own port, and a certificate is for a name, not a
|
||||
# port, so all of them share the one Caddy obtains for {$DATA_DOMAIN}.
|
||||
#
|
||||
# 443 S3 API path-style: https://<name>/<bucket>/<key>, the root of the host
|
||||
# 5432 PostgreSQL TLS terminated by the Layer 4 listener above
|
||||
# 9443 MinIO console
|
||||
# 5443 pgAdmin
|
||||
#
|
||||
# The S3 API is the one on the standard port because it is what other systems call: its host
|
||||
# appears in signed requests, and MinIO serves buckets from the root, so it cannot share the root
|
||||
# with another application. Opening https://<name>/ in a browser shows MinIO's XML error; that is
|
||||
# the API answering, not a fault.
|
||||
#
|
||||
# This site block is also what makes Caddy obtain and renew the certificate the Layer 4 PostgreSQL
|
||||
# listener presents.
|
||||
{$DATA_DOMAIN} {
|
||||
reverse_proxy minio:9000
|
||||
|
||||
log {
|
||||
|
|
@ -38,8 +41,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
# Browser-based MinIO console, separated from the S3 API hostname.
|
||||
{$MINIO_CONSOLE_DOMAIN} {
|
||||
# Browser-based MinIO console. MINIO_BROWSER_REDIRECT_URL must carry this port, or MinIO sends the
|
||||
# browser back to the S3 API's address.
|
||||
{$DATA_DOMAIN}:9443 {
|
||||
reverse_proxy minio:9001
|
||||
|
||||
log {
|
||||
|
|
@ -50,7 +54,7 @@
|
|||
|
||||
# Multi-user PostgreSQL administration UI. Authentication is handled by
|
||||
# pgAdmin; database permissions remain the responsibility of PostgreSQL roles.
|
||||
{$PGADMIN_DOMAIN} {
|
||||
{$DATA_DOMAIN}:5443 {
|
||||
reverse_proxy pgadmin:5050
|
||||
|
||||
log {
|
||||
|
|
|
|||
47
README.md
47
README.md
|
|
@ -1,11 +1,20 @@
|
|||
# PostgreSQL and MinIO public data stack
|
||||
|
||||
This Compose stack publishes four encrypted endpoints through Caddy:
|
||||
This Compose stack publishes four encrypted endpoints through Caddy, all on **one host name**
|
||||
(`DATA_DOMAIN`, here `data.example.com`), each on its own port:
|
||||
|
||||
- PostgreSQL on `postgres.example.com:5432` using the native PostgreSQL TLS negotiation;
|
||||
- the MinIO S3 API on `https://s3.example.com`;
|
||||
- the MinIO console on `https://minio.example.com`;
|
||||
- the multi-user pgAdmin interface on `https://pgadmin.example.com`.
|
||||
| Service | Address |
|
||||
|---|---|
|
||||
| MinIO S3 API | `https://data.example.com` (443) |
|
||||
| PostgreSQL | `data.example.com:5432`, using the native PostgreSQL TLS negotiation |
|
||||
| MinIO console | `https://data.example.com:9443` |
|
||||
| pgAdmin (multi-user) | `https://data.example.com:5443` |
|
||||
|
||||
One name means one DNS record and one certificate: a certificate is issued for a name, not a port,
|
||||
so every port above presents the same one. The S3 API is the one on the standard port because it is
|
||||
what other systems call and MinIO serves buckets from the root of its host. Opening
|
||||
`https://data.example.com/` in a browser therefore shows an XML error from MinIO; that is the API
|
||||
answering, not a fault.
|
||||
|
||||
PostgreSQL and MinIO have no directly published container ports. Caddy is the only public entry
|
||||
point; traffic from Caddy to the services stays on an internal Docker network. Caddy persists its
|
||||
|
|
@ -24,9 +33,10 @@ saved server definitions live in the `pgadmin-data` volume.
|
|||
|
||||
## Start
|
||||
|
||||
1. Create public `A`/`AAAA` records for the four names and point them to the server.
|
||||
2. Allow inbound TCP ports `80`, `443`, and `5432` in the host/cloud firewall. Restrict `5432` to
|
||||
known client address ranges whenever possible.
|
||||
1. Create public `A`/`AAAA` records for `DATA_DOMAIN` and point them to the server.
|
||||
2. Allow inbound TCP ports `80`, `443`, `5432`, `9443` and `5443` in the host/cloud firewall. Restrict
|
||||
`5432`, `9443` and `5443` to known client address ranges whenever possible: only `80` and `443`
|
||||
have to be open to the whole Internet, for certificate issuance.
|
||||
3. Copy the environment template and replace every placeholder:
|
||||
|
||||
```sh
|
||||
|
|
@ -43,7 +53,7 @@ saved server definitions live in the `pgadmin-data` volume.
|
|||
```
|
||||
|
||||
Ports 80 and 443 must reach Caddy from the public Internet for the usual ACME HTTP/TLS challenges.
|
||||
The names must be eligible for Let's Encrypt issuance; a restrictive DNS CAA record can refuse it.
|
||||
The name must be eligible for Let's Encrypt issuance; a restrictive DNS CAA record can refuse it.
|
||||
|
||||
## Connect
|
||||
|
||||
|
|
@ -51,14 +61,15 @@ PostgreSQL requires TLS at the public listener. `verify-full` both encrypts the
|
|||
that the certificate matches the hostname:
|
||||
|
||||
```sh
|
||||
psql "host=postgres.example.com port=5432 dbname=humainflow user=humainflow sslmode=verify-full"
|
||||
psql "host=data.example.com port=5432 dbname=humainflow user=humainflow sslmode=verify-full"
|
||||
```
|
||||
|
||||
MinIO/S3 clients use `https://s3.example.com`; administrators open
|
||||
`https://minio.example.com`. `MINIO_SERVER_URL` is set to the public S3 hostname so presigned URLs
|
||||
remain valid behind the reverse proxy.
|
||||
MinIO/S3 clients use `https://data.example.com` with path-style addressing
|
||||
(`https://data.example.com/<bucket>/<key>`); administrators open `https://data.example.com:9443`.
|
||||
`MINIO_SERVER_URL` is set to the public S3 address so presigned URLs remain valid behind the reverse
|
||||
proxy, and `MINIO_BROWSER_REDIRECT_URL` carries the console's port.
|
||||
|
||||
Open `https://pgadmin.example.com` and sign in with `PGADMIN_DEFAULT_EMAIL` and
|
||||
Open `https://data.example.com:5443` and sign in with `PGADMIN_DEFAULT_EMAIL` and
|
||||
`PGADMIN_DEFAULT_PASSWORD`. On the first login, register the database with these values:
|
||||
|
||||
- host: `postgres` (the Compose service name, not the public hostname);
|
||||
|
|
@ -81,3 +92,11 @@ intended.
|
|||
|
||||
Upgrade PostgreSQL one major version at a time using the PostgreSQL upgrade procedure. Updating an
|
||||
image tag alone does not migrate an existing database volume.
|
||||
|
||||
## Upgrading from the four-name layout
|
||||
|
||||
An earlier version used `POSTGRES_DOMAIN`, `MINIO_API_DOMAIN`, `MINIO_CONSOLE_DOMAIN` and
|
||||
`PGADMIN_DOMAIN`. Replace them in `.env` with a single `DATA_DOMAIN` (any one of the old names will
|
||||
do, as long as it resolves to this server), open ports `9443` and `5443`, and run
|
||||
`docker compose up -d --build`. Data volumes are untouched. Addresses change: the console moves from
|
||||
its own name to `:9443`, pgAdmin to `:5443`, and PostgreSQL clients connect to `DATA_DOMAIN`.
|
||||
|
|
|
|||
|
|
@ -44,8 +44,9 @@ services:
|
|||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:?set MINIO_ROOT_USER in .env}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?set MINIO_ROOT_PASSWORD in .env}
|
||||
# Required for presigned URLs generated while MinIO is behind Caddy.
|
||||
MINIO_SERVER_URL: https://${MINIO_API_DOMAIN:?set MINIO_API_DOMAIN in .env}
|
||||
MINIO_BROWSER_REDIRECT_URL: https://${MINIO_CONSOLE_DOMAIN:?set MINIO_CONSOLE_DOMAIN in .env}
|
||||
MINIO_SERVER_URL: https://${DATA_DOMAIN:?set DATA_DOMAIN in .env}
|
||||
# The console has its own public port on the same name, and the redirect must carry it.
|
||||
MINIO_BROWSER_REDIRECT_URL: https://${DATA_DOMAIN}:${CONSOLE_PUBLIC_PORT:-9443}
|
||||
command: ["server", "/data", "--console-address", ":9001"]
|
||||
volumes:
|
||||
- minio-data:/data
|
||||
|
|
@ -107,16 +108,16 @@ services:
|
|||
dockerfile: caddy.Dockerfile
|
||||
environment:
|
||||
TLS_CONTACT: ${TLS_CONTACT:?set TLS_CONTACT in .env}
|
||||
POSTGRES_DOMAIN: ${POSTGRES_DOMAIN:?set POSTGRES_DOMAIN in .env}
|
||||
MINIO_API_DOMAIN: ${MINIO_API_DOMAIN:?set MINIO_API_DOMAIN in .env}
|
||||
MINIO_CONSOLE_DOMAIN: ${MINIO_CONSOLE_DOMAIN:?set MINIO_CONSOLE_DOMAIN in .env}
|
||||
PGADMIN_DOMAIN: ${PGADMIN_DOMAIN:?set PGADMIN_DOMAIN in .env}
|
||||
DATA_DOMAIN: ${DATA_DOMAIN:?set DATA_DOMAIN in .env}
|
||||
ports:
|
||||
# 80/443 are used for ACME challenges, HTTPS and redirects.
|
||||
- "${PUBLIC_BIND_ADDRESS:-0.0.0.0}:${HTTP_PUBLIC_PORT:-80}:80"
|
||||
- "${PUBLIC_BIND_ADDRESS:-0.0.0.0}:${HTTPS_PUBLIC_PORT:-443}:443"
|
||||
# PostgreSQL-over-TLS is terminated by Caddy's Layer 4 module.
|
||||
- "${PUBLIC_BIND_ADDRESS:-0.0.0.0}:${POSTGRES_PUBLIC_PORT:-5432}:5432"
|
||||
# The MinIO console and pgAdmin, on the same name as everything else but their own ports.
|
||||
- "${PUBLIC_BIND_ADDRESS:-0.0.0.0}:${CONSOLE_PUBLIC_PORT:-9443}:9443"
|
||||
- "${PUBLIC_BIND_ADDRESS:-0.0.0.0}:${PGADMIN_PUBLIC_PORT:-5443}:5443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
# Certificates, private keys and the ACME account must survive restarts.
|
||||
|
|
|
|||
Loading…
Reference in New Issue