-
-
Notifications
You must be signed in to change notification settings - Fork 0
Deployment Guide
How to install openWCS and deploy it — on a local Linux box, a cloud VM, or as managed containers on AWS, Google Cloud, and Microsoft Azure.
What ships today. openWCS is built from source. A
Dockerfilefor every service and a ready-to-runplatform/docker-compose.ymlare committed, but the project does not yet publish prebuilt images, Helm charts, or Terraform. The cloud sections below are recipes: build the images yourself, push them to your registry, and wire them up with the platform's native primitives. Contributions of charts / IaC are very welcome — see Contributing.
For a developer build-and-run loop, see Getting Started. This page is about standing the system up for real.
- What you're deploying
- 1 · Build & publish the images
- 2 · Local Linux server
- 3 · A cloud VM (any provider)
- 4 · AWS — containers (ECS Fargate)
- 5 · Google Cloud (GKE / Cloud Run)
- 6 · Microsoft Azure (Container Apps / AKS)
- Production checklist
| Tier | Components | Notes |
|---|---|---|
| Edge |
gateway (8080) |
The only service that needs to be publicly reachable. Routes /api/<service>/**, validates JWTs (optional), forwards identity headers. |
| Domain services (Spring Boot, JRE 21) | master-data, inventory, process-engine, order-management, allocation, flow-orchestrator, txlog, iam, notification, integration-host, integration-sap, integration-manhattan | Stateless HTTP; all reach one PostgreSQL database (schema-per-service) and Kafka. Reach each other by hostname over HTTP. |
| Device adapters (Go) | conveyor, asrs, amr-geekplus, autostore, conveyor-sniffer | Talk equipment protocols ↔ the uniform device contract. The sniffer also needs L2 reachability to the conveyor network it learns from. |
| UI (React/Vite) | ui |
A static bundle (npm run build → dist/). Serve it from any static host and point it at the gateway. |
| Infrastructure | PostgreSQL 16 · Apache Kafka · Keycloak 25 (auth) · (optional) Schema Registry | In production, prefer managed Postgres + Kafka. |
Key wiring (env vars). Every Spring service takes:
SPRING_DATASOURCE_URL=jdbc:postgresql://<pg-host>:5432/openwcs
SPRING_DATASOURCE_USERNAME=openwcs
SPRING_DATASOURCE_PASSWORD=<secret>
SPRING_KAFKA_BOOTSTRAP_SERVERS=<broker:9092> # services that use Kafka
The gateway is told where the services live via OPENWCS_URI_<SERVICE> (e.g.
OPENWCS_URI_INVENTORY=http://inventory:8082); services that call each other use
OPENWCS_<TARGET>_BASE_URL. In Compose those are hostnames; in the cloud they become your
platform's internal DNS names (Cloud Map / Container Apps / k8s Service). See the committed
platform/docker-compose.yml
for the full, authoritative set.
Ports are listed in Getting Started.
Every deployment target consumes the same images, so build them once and push to your registry. Prerequisites on the build host: JDK 21, Docker, Go 1.25+, Node 20+.
git clone https://github.com/brettljausn-ai/openwcs.git && cd openwcs
# Pick your registry prefix:
# GHCR: ghcr.io/<org>
# ECR: <acct>.dkr.ecr.<region>.amazonaws.com
# GAR: <region>-docker.pkg.dev/<project>/<repo>
# ACR: <name>.azurecr.io
REG=ghcr.io/your-org
TAG=$(git rev-parse --short HEAD)
# Java jars (the Dockerfiles COPY build/libs/*.jar)
./gradlew bootJar
# Java services — the module directory is the build context
for m in gateway \
services/master-data services/inventory services/process-engine services/order-management \
services/allocation services/flow-orchestrator services/txlog services/iam services/notification \
services/integration-host services/integration-sap services/integration-manhattan; do
name="openwcs-$(basename "$m")"
docker build -t "$REG/$name:$TAG" "$m" && docker push "$REG/$name:$TAG"
done
# Go adapters — multi-stage, built from source
for a in conveyor asrs amr-geekplus autostore conveyor-sniffer; do
docker build -t "$REG/openwcs-$a-adapter:$TAG" "services/adapters/$a" \
&& docker push "$REG/openwcs-$a-adapter:$TAG"
done
# UI — static bundle (host it on a static service, or bake your own nginx image)
( cd ui && npm ci && npm run build ) # → ui/distAuthenticate to your registry first (docker login ghcr.io, aws ecr get-login-password …,
gcloud auth configure-docker …, or az acr login …).
Smallest real install: one box running everything via Docker Compose. Good for a pilot, a single line, or an on-prem edge server next to the equipment.
# Debian/Ubuntu — install Docker Engine + the compose plugin
sudo apt-get update && sudo apt-get install -y ca-certificates curl
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER" && newgrp docker
git clone https://github.com/brettljausn-ai/openwcs.git && cd openwcs
./gradlew bootJar # JDK 21 required to build
docker compose -f platform/docker-compose.yml --profile apps up --build -dOr one command — scripts/setup-demo.sh does all of the above on a fresh Ubuntu
22.04/24.04 box (installs Docker + JDK 21, clones to /opt/openwcs, builds, starts):
curl -fsSL https://raw.githubusercontent.com/brettljausn-ai/openwcs/main/scripts/setup-demo.sh | sudo bash
# add --auto-deploy (clone first, then run it) to also install the auto-deploy timerThis starts PostgreSQL, Kafka (+ZooKeeper), Keycloak (imports the openwcs realm), Schema
Registry, every Java service, the Go adapters, and the gateway. Check health and watch logs:
docker compose -f platform/docker-compose.yml ps
curl localhost:8080/actuator/health # gateway
docker compose -f platform/docker-compose.yml logs -f gatewayMake it production-ish on one host:
-
Run on boot — wrap the compose project in a
systemdunit (ExecStart=docker compose … up,ExecStop=docker compose … down,Restart=always), or addrestart: unless-stoppedto the services. -
Auto-deploy on
main— keep the box in sync with the repo automatically, either with a poll-basedsystemdtimer or a CI-gated self-hosted GitHub Actions runner. Both ship indeploy/and reusescripts/deploy.sh(fast-forward → rebuild → recompose, no-op when unchanged). -
TLS + a real hostname — put Caddy or nginx in front, terminating HTTPS and proxying
to
gateway:8080. Only the gateway (and the UI host) should be exposed; keep Postgres, Kafka, Keycloak, and the services on the internal Docker network. -
Persistence — the
pgdatavolume holds your system of record. Put it on durable storage and back it up (pg_dump/pg_basebackup); snapshot Keycloak's data too. -
Externalise the DB (optional) — point
SPRING_DATASOURCE_URLat a separate PostgreSQL host instead of the in-compose one for easier backups/HA. -
Security — set
OPENWCS_SECURITY_ENABLED=trueand change all default passwords (Postgres, Keycloak admin, realm users). See Security. -
Serve the UI — the
--profile appsstack already builds and serves the UI with nginx on host :80 (it proxies/api→ gateway), so browse the demo athttp://<host>/. For production, put your own reverse proxy / TLS in front of it, or hostui/distseparately and point it at the gateway URL.
An EC2 instance, GCE VM, Azure VM, or a droplet is just §2 on rented hardware — the fastest way to get a public, internet-reachable instance.
-
Provision a VM (start with 4 vCPU / 8–16 GB RAM; the full stack with Kafka is the heavy part) running a current Ubuntu/Debian.
-
Open only 443 (and 80 for the ACME challenge) in the firewall / security group. SSH from your IP only. Do not expose 5432/9092/8180.
-
Follow §2. Use Caddy for automatic Let's Encrypt TLS:
wcs.example.com { reverse_proxy /api/* gateway:8080 reverse_proxy /* ui:80 # or serve ui/dist directly }
-
For anything beyond a pilot, move the database to the provider's managed PostgreSQL and point
SPRING_DATASOURCE_URLat it — you get backups, failover, and patching for free.
When you outgrow a single VM (HA, autoscaling, rolling deploys), graduate to the managed-container options below.
Run each service as a Fargate task; use managed data services. (EKS is an alternative if you prefer Kubernetes — see §5's GKE recipe, which translates directly.)
Managed building blocks
| Need | AWS service |
|---|---|
| Images | ECR (one repo per image from §1) |
| PostgreSQL |
RDS for PostgreSQL 16 — one instance, database openwcs
|
| Kafka |
Amazon MSK (native Kafka) — set SPRING_KAFKA_BOOTSTRAP_SERVERS to the broker string |
| Service-to-service DNS |
ECS Service Connect / Cloud Map private namespace (e.g. *.openwcs.local) |
| Public entry |
ALB → the gateway service only (target port 8080, health check /actuator/health) |
| Secrets | Secrets Manager / SSM Parameter Store → injected as task env vars |
| UI |
S3 + CloudFront (upload ui/dist) |
Shape of it
-
aws ecr create-repositoryfor each image; push (§1) withREG=<acct>.dkr.ecr.<region>.amazonaws.com. -
Create the RDS instance and (optionally) MSK cluster in a VPC with private subnets.
-
Create an ECS cluster and a task definition per service. Each task's env mirrors the Compose file, but hostnames become Service Connect DNS names:
SPRING_DATASOURCE_URL = jdbc:postgresql://<rds-endpoint>:5432/openwcs SPRING_KAFKA_BOOTSTRAP_SERVERS = <msk-bootstrap-brokers> OPENWCS_URI_INVENTORY = http://inventory.openwcs.local:8082 # on the gateway task OPENWCS_ALLOCATION_BASE_URL = http://allocation.openwcs.local:8091 # on order-management, etc. -
Register each as an ECS Service (desired count ≥1) joined to the Service Connect namespace. Only the
gatewayservice sits behind the ALB; everything else stays private. -
Point CloudFront/Route 53 at the ALB; deploy the UI bundle to S3.
Tip: start the gateway + the services it fronts, prove
/api/.../actuator/healththrough the ALB, then scale out the adapters and integration services. Keep Keycloak as its own Fargate service (or use an existing IdP) and enableOPENWCS_SECURITY_ENABLEDonce tokens flow.
Recommended: GKE — because openWCS needs Kafka and a couple of always-on Kafka consumers
(inventory, the txlog relay), a Kubernetes cluster is the cleanest fit.
| Need | GCP service |
|---|---|
| Images |
Artifact Registry (<region>-docker.pkg.dev/<project>/openwcs) |
| PostgreSQL |
Cloud SQL for PostgreSQL 16, database openwcs
|
| Kafka | self-managed on GKE (e.g. Strimzi/Bitnami) or Confluent Cloud |
| Cluster | GKE Autopilot |
| Public entry |
GKE Ingress / Gateway API → the gateway Service |
| UI | Cloud Storage static site + Cloud CDN |
Each service becomes a Deployment + Service; the k8s Service name is the hostname, so
OPENWCS_URI_* / *_BASE_URL map straight onto http://inventory:8082, etc. — i.e. the Compose
env translates almost 1:1 into manifests. Put the DB password and Kafka creds in a Secret,
expose only the gateway through Ingress, and run Cloud SQL Auth Proxy (or private IP) for the DB.
Cloud Run also works for the stateless HTTP services (gateway + most domain services) with
Cloud SQL and Confluent Cloud for Kafka — use internal ingress + service-to-service IAM,
and set min-instances=1 on the Kafka-consuming services so projections keep up. If you'd rather
not manage that nuance, stay on GKE for the whole stack.
gcloud artifacts repositories create openwcs --repository-format=docker --location=<region>
gcloud auth configure-docker <region>-docker.pkg.dev
# …push images from §1 with REG=<region>-docker.pkg.dev/<project>/openwcs, then apply your manifestsRecommended: Azure Container Apps (ACA) — managed, scale-to-zero-capable containers with a built-in internal DNS, which suits the service mesh well.
| Need | Azure service |
|---|---|
| Images | Azure Container Registry (ACR) |
| PostgreSQL |
Azure Database for PostgreSQL — Flexible Server, database openwcs
|
| Kafka | Azure Event Hubs (Kafka-compatible endpoint) or Kafka on AKS |
| Runtime | Azure Container Apps environment (one app per service) |
| Public entry | external ingress on the gateway app; all others internal ingress |
| UI | Azure Static Web Apps or Blob Storage + CDN |
Within an ACA environment, apps reach each other at https://<app-name>.internal.<env-domain> (or
simply the app name) — so the service URLs become those internal FQDNs. Event Hubs speaks the Kafka
protocol, so SPRING_KAFKA_BOOTSTRAP_SERVERS=<namespace>.servicebus.windows.net:9093 with SASL
config works for the producers/consumers. Store the DB and Event Hubs connection strings in the
environment's secrets.
az acr create -n <acr> -g <rg> --sku Standard && az acr login -n <acr>
# push images from §1 with REG=<acr>.azurecr.io
az containerapp env create -n openwcs -g <rg> -l <region>
az containerapp create -n gateway -g <rg> --environment openwcs \
--image <acr>.azurecr.io/openwcs-gateway:<tag> --target-port 8080 --ingress external
# …repeat per service with --ingress internal and the SPRING_*/OPENWCS_* env varsAKS is the alternative for full Kubernetes control; the manifest model from §5 applies unchanged (swap Cloud SQL→Flexible Server, Artifact Registry→ACR).
Regardless of target:
-
One PostgreSQL, many schemas. All services share a single managed database (
openwcs) with a schema per service. Size it for your busiest service, enable automated backups + PITR. - Managed Kafka. Use MSK / Event Hubs / Confluent rather than self-managing brokers. The transaction log → Kafka stream is the backbone; size partitions and retention deliberately.
- Expose only the gateway. Keep services, DB, Kafka, and Keycloak on the private network. Terminate TLS at the edge (LB / ingress / reverse proxy).
-
Turn security on. Set
OPENWCS_SECURITY_ENABLED=true, run Keycloak (or your IdP) with theopenwcsrealm, rotate every default password/secret, and store secrets in the platform's secret manager — never in images. See Security. -
Scaling. The gateway and stateless domain services scale horizontally. Mind the
Kafka-consuming services (
inventory,txlogrelay) — their throughput is bound by topic partitions, and they should not scale to zero if you need live projections. -
Adapters live near the equipment. Device adapters (and especially the conveyor-sniffer,
which needs L2 access to the conveyor network and a configured
WAREHOUSE_ID/ALLOWED_IPS) usually run at the edge/on-prem, not in the cloud. They reach the WCS over HTTPS. -
Observability & backups. Ship logs/metrics (
/actuatorendpoints are exposed), alert on consumer lag and gateway 5xx, and rehearse a database restore before go-live.
- Getting Started — local build & run, ports
- Architecture · Services — what each component does and owns
- Security — JWT, RBAC, Keycloak realm
- Equipment Integration — adapters & the device contract (edge deployment)
openWCS — open-source Warehouse Control System · summarized from build.md & docs/AS-BUILT.md (the repo docs are authoritative).
Design
Flows
- Areas
- Inbound and Inventory
- Slotting and Replenishment
- Goods-to-Person Stations
- Outbound Flow
- Equipment Integration
- Transport Overview
- Process Designer
- Mobile Process Designer
- Hardware Visualisation
- Host Integration
Reporting & Dashboards
Operations