Skip to main content

Deployment Overview

Complete infrastructure and deployment guide for the Ampra platform. Covers local development, Docker containerization, CI/CD pipeline, and production architecture.


Infrastructure Topology


Domain Configuration

DomainServicePortTLS
ampra.solarReact UI (nginx)80Let's Encrypt via Traefik
api.ampra.solarASP.NET Core API80Let's Encrypt via Traefik
docs.ampra.solarDocusaurus (nginx)80Let's Encrypt via Traefik
minio.ampra.solarMinIO Object Storage9000Let's Encrypt via Traefik
emqx.ampra.solarEMQX Dashboard18083Let's Encrypt via Traefik
ampra.solar:1883MQTT Broker1883Raw TCP (direct port expose)

Container Inventory

ContainerImagePurposePersistent Volume
ampra-apiampra-api:latest.NET 10 REST API
ampra-uiampra-ui:latestReact SPA (nginx)
ampra-docsampra-docs:latestDocusaurus site (nginx)
ampra-mlampra-ml:latestPython ML service
ampra-ingestionampra-ingestion:latestMQTT ingestion worker
ampra-dbpostgres:16-alpinePostgreSQL databaseampra-db-data
ampra-mongomongo:8.0MongoDB databaseampra-mongo-data
ampra-minioquay.io/minio/minioS3-compatible storageampra-minio-data
ampra-redisredis:7-alpineCache and job storeampra-redis-data
ampra-emqxemqx/emqx:5.8MQTT brokerampra-emqx-data

Docker Images

API Image (ampra-api)

Multi-stage build from the solution root:

# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
# Restores Ampra.Web, Ampra.Application, Ampra.Infrastructure, Ampra.Core
# Publishes release build

# Stage 2: Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
# Runs as non-root user ($APP_UID)
# Exposes port 80

Build context: Solution root
Dockerfile: src/Ampra.Web/Dockerfile

UI Image (ampra-ui)

# Stage 1: Build
FROM node:20-alpine AS build
# Accepts VITE_API_URL build argument
# Runs npm install + npm build (Vite)

# Stage 2: Serve
FROM nginx:alpine
# Copies dist/ to nginx html directory
# Uses custom nginx.conf for SPA routing

Build argument: VITE_API_URL=https://api.ampra.solar
Build context: src/Ampra.UI/

ML Image (ampra-ml)

FROM python:3.12-slim
# Installs requirements (Flask, XGBoost, scikit-learn, pandas, etc.)
# Runs as non-root 'appuser'
# Serves via Gunicorn (2 workers, 600s timeout)

Build context: src/Ampra.ML/

MQTT Ingestion Image (ampra-ingestion)

# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
# Restores and publishes Ampra.MqttIngestion + Ampra.Core

# Stage 2: Runtime
FROM mcr.microsoft.com/dotnet/runtime:10.0 AS runtime
# No web server — runs as background worker

Build context: Solution root
Dockerfile: src/Ampra.MQTT/Dockerfile

Docs Image (ampra-docs)

# Stage 1: Build
FROM node:22-alpine AS build
# Runs npm ci + npm run build (Docusaurus)

# Stage 2: Serve
FROM nginx:alpine
# Serves static build with asset caching (1 year for static assets)

Build context: src/Ampra.Docs/


Networking

All containers are connected via the web Docker network. Traefik discovers containers through Docker labels.

Traefik Label Pattern

traefik.enable: true
traefik.http.routers.{name}.rule: "Host(`{domain}`)"
traefik.http.routers.{name}.entrypoints: websecure
traefik.http.routers.{name}.tls.certresolver: myresolver
traefik.http.services.{name}.loadbalancer.server.port: {port}

Inter-Service Communication

FromToProtocolAddress
APIPostgreSQLTCPampra-db:5432
APIMongoDBTCPampra-mongo:27017
APIRedisTCPampra-redis:6379
APIMinIOHTTPampra-minio:9000
APIML ServiceHTTPampra-ml:5050
EMQXAPIHTTPampra-api:80
IngestionEMQXMQTTampra-emqx:1883
IngestionMongoDBTCPampra-mongo:27017
IngestionPostgreSQLTCPampra-db:5432
ML ServiceMongoDBTCPampra-mongo:27017
ML ServiceRedisTCPampra-redis:6379
ML ServiceMinIOHTTPampra-minio:9000