Self-Hosting SecureExec with Docker Compose

One of SecureExec's core design goals is that you should be able to run the entire platform on your own infrastructure with a single command. This post covers a production-ready Docker Compose deployment, including TLS, Elasticsearch security, and basic hardening.

Architecture Overview

A full SecureExec deployment consists of four services:

ServiceImagePurpose
serversecureexec-servergRPC ingestion server (port 50051)
backendsecureexec-backendREST API & webapp backend (port 8080)
frontendsecureexec-frontendNext.js UI (port 3000)
elasticsearchelasticsearch:8.xEvent storage and search

The server and backend communicate over an internal Docker network — agents talk only to the server, and the browser talks only to the frontend/backend.

Environment Configuration

All secrets are injected via environment variables. Copy .env.example to .env and configure:

# Elasticsearch
ELASTICSEARCH_PASSWORD=your-strong-password

# Webapp backend
DATABASE_URL=postgres://user:pass@postgres/secureexec
SECRET_KEY=your-jwt-secret

# gRPC server — points to webapp backend for token validation
WEBAPP_BACKEND_URL=http://backend:8080

# Optional: TLS for the gRPC server
SECUREEXEC_TLS_CERT=/certs/server.crt
SECUREEXEC_TLS_KEY=/certs/server.key

Enabling TLS on the gRPC Server

Agents connect to the gRPC server directly. For production, you should terminate TLS at the server itself (not a reverse proxy) so agents can verify the server certificate:

# Generate a self-signed CA and server cert
openssl genrsa -out ca.key 4096
openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -subj "/CN=SecureExec CA"
openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr -subj "/CN=secureexec-server"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365

Mount the certs into the server container and set the env vars above. Distribute ca.crt to your agents.

Elasticsearch Security

Never run Elasticsearch with security disabled in production. The Compose stack enables Elasticsearch security by default. The server and backend both use basic auth (elastic user) to communicate with Elasticsearch.

Set ELASTICSEARCH_PASSWORD to a strong password. The server reads this from ELASTICSEARCH_PASSWORD and the backend from the same variable.

Reverse Proxy

For the webapp, put Nginx or Caddy in front of the frontend on port 443 and proxy /api to the backend. The gRPC server should be exposed directly on port 50051 (or a custom port) with its own TLS certificate.

Upgrading

SecureExec uses per-component version files (server/version, webapp/backend/version, webapp/frontend/version). When a new version is released:

docker compose pull
docker compose up -d

Elasticsearch mappings are updated automatically on startup through index template management.

Monitoring

The gRPC server and webapp backend both emit structured JSON logs via tracing. Ship logs to your SIEM or log aggregator. Key events to alert on:

  • token validation failed — repeated failures may indicate a brute-force attempt
  • elasticsearch bulk index failed — events are being dropped
  • stream error — agent connectivity issues