Overview
Phonemos uses an Nginx reverse proxy as the single external entry point. Nginx terminates TLS on ports 80 (redirect) and 443 (HTTPS) and routes requests to internal services over Docker networks. All inter-service communication happens on private Docker networks that are not exposed to the host.
Docker Networks
Three Docker networks isolate traffic between service groups:
phonemosIngress
Services that need to be reachable from the Nginx reverse proxy:
Service | Role |
|---|---|
ingress | Nginx reverse proxy |
frontend | Web UI |
hasura | GraphQL API |
backend | Main backend |
backend-pdf | PDF generation |
keycloak | Authentication |
minio-filestore | Object storage |
phonemos
Internal application communication (not exposed through Nginx):
Service | Role |
|---|---|
hasura, backend, backend-pdf | Application services (also on phonemosIngress) |
postgres | PostgreSQL database |
redis | Cache and job queue |
pandoc, converter-* | Document converters (Pandoc, Draw.io, BPMN, LibreOffice, Linux tools) |
confluence-converter | Confluence import converter |
youtrack-connector, jira-dc-connector | External connectors (optional) |
phonemosKeycloak
Isolated network for Keycloak and its dedicated database (keycloak and keycloak-postgres). Note that keycloak is on both phonemosKeycloak and phonemosIngress, bridging the two networks.
Traffic Flow
External traffic:
A client sends a request to the server on port 443 (or 80, which redirects to 443).
Nginx terminates TLS and inspects the URL path.
Based on the path, Nginx proxies the request to the appropriate upstream service on the phonemosIngress network.
Internal traffic:
hasura and backend communicate with postgres and redis on the phonemos network.
backend dispatches conversion jobs to converter services via redis on the phonemos network.
keycloak communicates with keycloak-postgres on the isolated phonemosKeycloak network.
No internal ports are published to the host. Only ports 80 and 443 are exposed externally.
Routing Table
URL Path | Upstream | Port | Location File |
|---|---|---|---|
/ | frontend | 8080 | phonemos.loc |
/v1/*, /v1alpha1/*, /v2/*, /healthz | hasura | 8080 | phonemos.loc |
/console | hasura | 8080 | phonemos.loc |
/api/pdf | backend-pdf | 8080 | phonemos.loc |
/_files | backend | 8081 | phonemos.loc |
/_api/scim | backend | 8082 | scim.loc |
/auth | keycloak | 8080 | keycloak.loc |
/phonemos-files* | minio-filestore | 9000 | minio.loc |
Ingress / Nginx Configuration
Nginx configuration is split across several files:
File | Location in container | Purpose |
|---|---|---|
nginx.conf | /etc/nginx/nginx.conf | Main config (worker settings, gzip, log format) |
phonemos.conf | /etc/nginx/conf.d/phonemos.conf | Server blocks (HTTP redirect, HTTPS with TLS) |
routes.conf | /etc/nginx/routes.loc | Location includes (which .loc files to load) |
servers.conf | /etc/nginx/servers.loc | Additional server blocks |
*.loc | /etc/nginx/conf.d/*.loc | Individual location routing rules |
Key Settings
Setting | Value |
|---|---|
HTTP/2 | Enabled |
Client max body size | 50 MB |
Proxy connect timeout | 5 seconds |
Proxy send/read timeout | 60 seconds |
Proxy buffering | Off |
Gzip | On |
TLS Certificates
The setup script supports three TLS modes, configured via TLS_TYPE in /etc/phonemos/setup.conf:
Public certificate — provide your .crt and .key files during setup. Recommended for production.
Self-signed — generated automatically using OpenSSL. Added to system CA store and a Java keystore is created. Suitable for testing.
Skip — no certificate configured. You must set up TLS manually.
Certificate files are located at /etc/phonemos/ingress/certs/cert.crt and /etc/phonemos/ingress/certs/cert.key.
DNS and Firewall
DNS: Create an A-record (or CNAME) pointing your hostname to the server's IP address. The hostname must be resolvable for Keycloak and the application to function correctly.
Firewall: Only two ports need to be accessible externally:
Port | Protocol | Purpose |
|---|---|---|
80 | TCP | HTTP (redirects to HTTPS) |
443 | TCP | HTTPS (all application traffic) |
All other ports (8080, 8081, 8082, 9000, 5432, 6379) are internal to Docker networks and are not published to the host.
Service Discovery
Nginx uses Docker's built-in DNS resolver (127.0.0.11) to resolve container names to IP addresses at request time. Each location block uses a variable to hold the upstream name, forcing Nginx to resolve DNS on every request rather than caching it at startup:
1
2
3
4
5
location / {
resolver 127.0.0.11 valid=30s ipv6=off;
set $upstream_frontend frontend;
proxy_pass http://$upstream_frontend:8080$request_uri;
}This ensures Nginx handles container restarts gracefully — if a container gets a new IP after a restart, Nginx resolves the updated address within 30 seconds.
Customization
Adding Routes
Edit /etc/phonemos/ingress/routes.conf to include or exclude location files. Comment out lines to disable routing to specific services (e.g. if you use an external Keycloak or MinIO).
Adding Server Blocks
Edit /etc/phonemos/ingress/servers.conf to add additional Nginx server blocks (e.g. for a separate subdomain or custom redirect rules).
Docker Compose Overlay
Edit /etc/phonemos/ingress/overlay.yaml to customize the ingress Docker Compose configuration. After making changes, restart the ingress service:
1
sudo systemctl restart phonemos-ingress