diff --git a/.env.example b/.env.example index 56f6f70..8893f73 100644 --- a/.env.example +++ b/.env.example @@ -40,6 +40,14 @@ COMPOSE_PROJECT_NAME=hub # Used by docker-compose.traefik.yml to configure routing rules # TRAEFIK_DOMAIN=meshcore.example.com +# Router priority for Traefik (higher = matched first) +# Use a higher value for more specific subdomain instances to avoid +# conflicts with wildcard routes from other instances on the same host. +# Production: 10 (default) +# Staging: 20 +# MQTT broker: 30 +# TRAEFIK_PRIORITY=10 + # Docker image version tag to use # Options: latest, main, v1.0.0, etc. IMAGE_VERSION=latest diff --git a/README.md b/README.md index e1d0c57..18b16b8 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,24 @@ docker compose -f docker-compose.yml -f docker-compose.prod.yml -f docker-compos This routes the web dashboard and API to `TRAEFIK_DOMAIN` with automatic TLS. +#### Multi-Instance Deployments + +To run multiple Hub instances (e.g., production + staging) on the same Docker host, set `TRAEFIK_PRIORITY` to control which router wins when domains overlap. Higher values are matched first: + +```bash +# Production (.env) +COMPOSE_PROJECT_NAME=hub +TRAEFIK_DOMAIN=example.com +TRAEFIK_PRIORITY=10 + +# Staging (.env) — separate directory with its own config +COMPOSE_PROJECT_NAME=hub-beta +TRAEFIK_DOMAIN=beta.example.com +TRAEFIK_PRIORITY=20 +``` + +This ensures `beta.example.com` (priority 20) is matched before the production wildcard `*.example.com` (priority 10). For other services on the same network (e.g., an MQTT broker at `mqtt.example.com`), use an even higher priority (e.g., 30). + ### Adding Remote Observers Other operators can run their own [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture) instance and publish decoded packets to your MeshCore Hub. They can also optionally contribute to the LetsMesh network. diff --git a/docker-compose.traefik.yml b/docker-compose.traefik.yml index eca9031..e0b9c51 100644 --- a/docker-compose.traefik.yml +++ b/docker-compose.traefik.yml @@ -6,6 +6,13 @@ # Set TRAEFIK_DOMAIN in your .env file to the hostname for this instance. # The web service matches the apex domain and all subdomains (e.g. www.meshcore.example.com). # +# For multi-instance deployments (e.g. production + staging on the same host), +# set TRAEFIK_PRIORITY to control which router wins when domains overlap. +# Higher priority = matched first. Recommended values: +# Production: 10 (default) +# Staging: 20 +# MQTT broker: 30 (in separate repo, same proxy-net) +# # Prerequisites: # - Traefik configured with Docker provider and attached to proxy-net # - TRAEFIK_DOMAIN set in .env (e.g., TRAEFIK_DOMAIN=meshcore.example.com) @@ -19,6 +26,7 @@ services: - "traefik.enable=true" - "traefik.http.services.${COMPOSE_PROJECT_NAME:-hub}-api.loadbalancer.server.port=8000" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-api.rule=Host(`${TRAEFIK_DOMAIN}`) && (PathPrefix(`/metrics`) || PathPrefix(`/health`))" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-api.priority=${TRAEFIK_PRIORITY:-10}" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-api.entrypoints=websecure" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-api.tls=true" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-api.tls.certresolver=default" @@ -29,6 +37,7 @@ services: - "traefik.enable=true" - "traefik.http.services.${COMPOSE_PROJECT_NAME:-hub}-web.loadbalancer.server.port=8080" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-web.rule=Host(`${TRAEFIK_DOMAIN}`) || HostRegexp(`^.+\\.${TRAEFIK_DOMAIN}$`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-web.priority=${TRAEFIK_PRIORITY:-10}" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-web.entrypoints=websecure" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-web.tls=true" - "traefik.http.routers.${COMPOSE_PROJECT_NAME:-hub}-web.tls.certresolver=default"