Skip to content

On-Premise Deployment

Docker Compose Deployment on Rocky Linux / RHEL

Document Version: 1.0.0
Last Updated: 2026-10-28
License Tier: All


1. Architecture Overview

graph LR
    FW["🛡️ Firewall"] --> Edge["🌐 Edge (nginx)<br/>(TLS Termination)<br/>:443 / :80"]
    Edge -->|"/api/, /swagger"| BE["⚙️ API Server<br/>:8443"]
    Edge -->|"/ and /bff"| FE["🖥️ Web Interface + BFF<br/>:3000"]
    FE -->|"HTTPS, verified"| BE
    FW --> OCSP["📜 OCSP Responder<br/>:8081"]
    FW --> Docs["📚 Documentation<br/>:8088"]
    BE --> PG["🗄️ PostgreSQL<br/>:5432"]
    BE --> Redis["⚡ Redis<br/>:6379"]

    classDef network fill:#F5F5F5,stroke:#9E9E9E,stroke-width:2px,color:#424242
    classDef app fill:#EBF5FB,stroke:#2196F3,stroke-width:2px,color:#1565C0
    classDef data fill:#E8F5E9,stroke:#4CAF50,stroke-width:2px,color:#2E7D32

    class FW,Edge network
    class BE,OCSP,FE,Docs app
    class PG,Redis data

The Compose kit runs these containers: edge (nginx, the only service that terminates TLS for the web interface), frontend (Nuxt web interface with its server, the BFF), backend, ocsp, docs and init-certs (prepares the certificates). The OCSP responder (8081) and the documentation (8088) are published on their own ports.

2. System Requirements

Component Minimum Recommended
OS Rocky Linux 9.x / RHEL 9.x Rocky Linux 9.4+
CPU 2 cores 4+ cores
RAM 4 GB 8+ GB
Storage 50 GB SSD 100+ GB SSD
Docker Engine 24+ Latest stable
Docker Compose 2.20+ Latest stable

3. Installation

Step 1: Install Docker

# Rocky Linux 9 / RHEL 9
sudo dnf config-manager --add-repo \
  https://download.docker.com/linux/rhel/docker-ce.repo

sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

sudo systemctl enable --now docker
sudo usermod -aG docker $USER

Step 2: Prepare Directory Structure

sudo mkdir -p /opt/mazevault/{data,config,certs,backups}
cd /opt/mazevault

Step 3: Load Container Images

For air-gapped environments, load the pre-built images from the offline package:

# Extract offline package
tar xzf mazevault-1.8.0-offline.tar.gz

# Load Docker images
docker load < images/mazevault-backend.tar
docker load < images/mazevault-frontend.tar
docker load < images/mazevault-ocsp.tar
docker load < images/postgres-15-alpine.tar
docker load < images/redis-7-alpine.tar
docker load < images/nginx-alpine.tar

For connected environments, images and the Compose kit come from the MazeVault Harbor (registry.mazevault.com/mazevault). Use the robot account you received from MazeVault (quote it, the name contains $). The Compose kit for release vX.Y.Z contains the installer, upgrade and rollback scripts, certificate helpers, docker-compose.yml, .env.example and SHA256SUMS:

oras login registry.mazevault.com -u 'robot$mazevault+yourcompany'
oras pull registry.mazevault.com/mazevault/compose-kit:vX.Y.Z -o mazevault-kit
cd mazevault-kit
sha256sum -c SHA256SUMS            # stop and contact MazeVault if any file fails
sudo MAZEVAULT_REGISTRY_USER='robot$mazevault+yourcompany' bash install-mazevault.sh --version vX.Y.Z

oras pull does not keep the executable bit, so run the kit scripts with bash. The installer logs in to the registry (it prompts for the password when MAZEVAULT_REGISTRY_PASSWORD is not set) and pulls the images. To use your own mirror, run bash mirror-to-registry.sh from the kit and install with --registry <your-registry>/mazevault.

The installer installs the kit's own docker-compose.yml into the install directory (/opt/mazevault, or --dir), so run it from the extracted kit; it stops with an error when docker-compose.yml is not next to it. For automation, MAZEVAULT_NO_SYSTEMD=1 skips creating the systemd service and all systemctl calls, and MAZEVAULT_COMPOSE_PROJECT sets the Docker Compose project name (default mazevault; pass the same -p to later docker compose commands).

Installations of v1.0.60 and older pull from GHCR (ghcr.io/mazevault). To move one to Harbor, docker login registry.mazevault.com with the robot account and re-run the installer from the new kit with --registry registry.mazevault.com/mazevault --version vX.Y.Z; without --registry it keeps its current registry.

Before running docker compose up -d, validate that the required tags exist (after docker login registry.mazevault.com):

for img in mazevault-backend mazevault-frontend mazevault-edge mazevault-ocsp mazevault-docs mazevault-init-certs; do
    docker manifest inspect "registry.mazevault.com/mazevault/${img}:vX.Y.Z" >/dev/null
done

If any check fails, do not continue with rollout on latest; switch to a known-good pinned release tag or use the offline package.

Step 4: Configure Environment

Create the environment file /opt/mazevault/.env:

# Database
POSTGRES_HOST=client-postgres
POSTGRES_PORT=5432
POSTGRES_USER=mazevault
POSTGRES_PASSWORD=<strong-password>
POSTGRES_DB=mazevault

# Redis
REDIS_HOST=client-redis
REDIS_PORT=6379
REDIS_PASSWORD=<strong-password>

# Application
APP_DOMAIN=vault.example.com
APP_PORT=8080
APP_ENV=production
TLS_ENABLED=true

# License
LICENSE_KEY=<your-license-key>

# Encryption (generate with: openssl rand -hex 32)
MASTER_KEY=<64-char-hex-string>

Master Key

The MASTER_KEY is the root encryption key for all secrets. Back it up securely — loss of this key means loss of access to all encrypted data. Store a copy in a physically separate, secure location.

Step 5: Configure TLS Certificates

Place your TLS certificates in /opt/mazevault/certs/:

# Required files:
/opt/mazevault/certs/server.crt    # Server certificate (PEM)
/opt/mazevault/certs/server.key    # Private key (PEM)
/opt/mazevault/certs/ca.crt        # CA chain (PEM)

See TLS Configuration for detailed certificate setup.

Step 6: Deploy

cd /opt/mazevault
docker compose up -d

Step 7: Verify Deployment

# Check all containers are running
docker compose ps

# Check API health
curl -sk https://localhost/api/v1/health | jq .

# Check logs
docker compose logs backend --tail=50

4. Edge Container

The kit's edge container (nginx) terminates TLS with server.crt and server.key from the certificate directory (TLS 1.2 and 1.3) and routes requests. You do not need to edit its configuration:

Request Goes to
port 80 redirect to https://
/api/ (including the agent websocket /api/v1/agents/me/connect) backend
/swagger backend
everything else (pages, /bff/*) frontend
  • Requests may take up to 300 seconds, agent websockets up to 3600 seconds, uploads up to 50 MB.
  • The edge appends the client address to X-Forwarded-For. The backend trusts it only from TRUSTED_PROXIES, which defaults to the kit subnet MAZEVAULT_SUBNET (172.31.250.0/24). If you put a load balancer in front of the edge on another private range, add it to TRUSTED_PROXIES in .env.
  • The edge forwards to the backend without verifying the backend certificate (an internal hop on the private Docker network). The web interface server (BFF) does verify it, against ca-bundle.crt.
  • The edge adds no security headers of its own. The web application sends HSTS, CSP, COEP and the other headers.
  • The edge is hardened: read-only filesystem, no new privileges, all capabilities dropped, 64 MB memory limit (EDGE_MEMORY_LIMIT). The certificate scripts restart it after an import or renewal.
  • The OCSP responder (8081) and the documentation (8088) are published on their own ports, not through the edge.

5. Firewall Configuration

# Rocky Linux / RHEL with firewalld
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

# Verify
sudo firewall-cmd --list-all

Warning

Do not expose ports 5432 (PostgreSQL) or 6379 (Redis) to the network. These must only be accessible within the Docker network. Agents and API clients reach the API through the edge on 443 (the kit also publishes the backend itself on BACKEND_PORT, default 8443; restrict it with the firewall if you do not need it).

Upgrading the Compose Kit

upgrade-mazevault.sh backs up your installation and then installs the new kit's docker-compose.yml. Run the upgrade script shipped in the new kit (oras pull registry.mazevault.com/mazevault/compose-kit:vX.Y.Z -o mazevault-kit, then sudo bash mazevault-kit/upgrade-mazevault.sh --version vX.Y.Z), or for an offline upgrade pass the new bundle with --offline (its docker-compose.yml is installed too); not the copy in the installation directory. Run with an older kit's docker-compose.yml (no edge service), the script stops before changing anything and names the command. The Docker network frontend is recreated with the fixed subnet MAZEVAULT_SUBNET (default 172.31.250.0/24), which causes a brief downtime. Before it stops anything, the script checks that the subnet does not overlap another Docker network or a host route; if it does, it stops with the old stack still running, and you set a free MAZEVAULT_SUBNET in .env and run it again. The new images are pulled (or loaded from the bundle) before the compose file and IMAGE_TAG are switched, so a failed pull stops the script with the old stack, compose file and IMAGE_TAG unchanged. An offline upgrade sets IMAGE_REGISTRY to the registry prefix of the bundle's images (an offline install from v1.0.60 has ghcr.io/mazevault) and stops the same way when an image of the new compose file is not in the bundle. If docker compose up refuses the changed network, run docker compose down (without -v, which would delete the data volumes), then docker compose up -d.

If you use a custom FRONTEND_PORT and FRONTEND_URL has no port, the script prints the exact NUXT_PUBLIC_ORIGIN=<base>:<port> line to add to .env; without it the web interface refuses sign-ins (the origin must equal the address in the browser).

sudo systemctl enable mazevault

Automatic systemd integration (since vX.X)

The install script (sudo bash install-mazevault.sh or sudo bash install-mazevault-offline.sh) now automatically creates and enables the systemd service for MazeVault. You do not need to perform the manual steps below unless you are customizing the service or using a non-standard deployment.

Note: The install script must be run as root (sudo).

To manually create or customize the systemd service:

sudo cat > /etc/systemd/system/mazevault.service << 'EOF'
[Unit]
Description=MazeVault Enterprise Secrets Manager
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/mazevault
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=120

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable mazevault

7. Offline Deployment Package

For air-gapped environments, the offline deployment package includes:

Component Format Size (approx.)
Backend image .tar ~150 MB
Frontend image .tar ~50 MB
OCSP image .tar ~30 MB
PostgreSQL image .tar ~80 MB
Redis image .tar ~30 MB
Nginx image .tar ~20 MB
Docker Compose config .yml <1 KB
Documentation .tar (static HTML) ~10 MB
Total ~370 MB

Contact your MazeVault account manager to obtain the offline deployment package.