Architecture
Understand how Haloy’s components work together to manage your deployments.
System Components
Haloy consists of several components working in harmony:
- Haloy CLI (
haloy) - Command-line interface for deployments from your local machine - Haloy Daemon (
haloyd) - Service running on your server that handles orchestration, routing, and SSL - Application Containers - Your deployed applications orchestrated by
haloyd
Component Overview
Haloy CLI (haloy)
Runs on: Your local development machine, CI/CD systems, or any machine that can reach your server’s API
Purpose: Trigger deployments and manage applications
Key Functions:
- Read and validate configuration files
- Build Docker images locally (optional)
- Upload images to servers
- Send deployment commands to
haloydAPI - Display deployment status and logs
Location: ~/.local/bin/haloy
See the haloy CLI command reference for available commands.
Haloy Daemon (haloyd)
Runs on: Your server (as a native systemd service)
Purpose: Container orchestration, reverse proxy, and SSL management
Key Functions:
- Accept deployment commands via REST API
- Pull or load Docker images
- Start and stop application containers
- Monitor container health
- Route traffic via built-in reverse proxy with host-based routing
- Terminate SSL/TLS with automatic certificate management via ACME (Let’s Encrypt)
- Track deployment history for rollbacks
Configuration: /etc/haloy/haloyd.yaml
Data storage: /var/lib/haloy/
See the haloyd command reference for available commands.
Built-in Reverse Proxy
The haloyd daemon includes a purpose-built reverse proxy that handles all traffic routing:
Key Features:
- HTTP/HTTPS reverse proxy with TLS termination
- Host-based routing to application containers
- SNI-based certificate selection (including wildcard support)
- Automatic HTTP to HTTPS redirects
- ACME challenge passthrough for Let’s Encrypt
- WebSocket support with bidirectional tunneling
- Connection pooling for backend connections
- Atomic configuration updates without restarts
Listens on: Ports 80 (HTTP) and 443 (HTTPS)
Application Containers
Runs on: Your server
Purpose: Your deployed applications
Managed by: haloyd
Networking: Connected to Haloy’s Docker network
Health monitoring: Via configured health check endpoints
Architecture Diagram
┌─────────────────────┐
│ Developer Machine │
│ │
│ ┌──────────────┐ │
│ │ haloy CLI │ │
│ └──────┬───────┘ │
└─────────┼───────────┘
│ HTTPS
│ (API calls)
▼
┌─────────────────────────────────────────┐
│ Server │
│ │
│ ┌──────────────────┐ │
│ │ haloyd (systemd) │ │
│ │ │ │
│ │ - API Server │ │
│ │ - Orchestration │ │
│ │ - Reverse Proxy │ │
│ │ - SSL/TLS │ │
│ │ Ports: 80, 443 │ │
│ └────┬─────────────┘ │
│ │ Routes traffic │
│ │ │
│ ├──────────┬──────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ App │ │ App │ │ App │ │
│ │ (8080) │ │ (8080) │ │ (8080) │ │
│ └────────┘ └────────┘ └────────┘ │
│ Replica 1 Replica 2 Replica 3 │
└─────────────────────────────────────────┘
┌─────────────────────┐
│ Developer Machine │
│ │
│ ┌──────────────┐ │
│ │ haloy CLI │ │
│ └──────┬───────┘ │
└─────────┼───────────┘
│ HTTPS
│ (API calls)
▼
┌─────────────────────────────────────────┐
│ Server │
│ │
│ ┌──────────────────┐ │
│ │ haloyd (systemd) │ │
│ │ │ │
│ │ - API Server │ │
│ │ - Orchestration │ │
│ │ - Reverse Proxy │ │
│ │ - SSL/TLS │ │
│ │ Ports: 80, 443 │ │
│ └────┬─────────────┘ │
│ │ Routes traffic │
│ │ │
│ ├──────────┬──────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ App │ │ App │ │ App │ │
│ │ (8080) │ │ (8080) │ │ (8080) │ │
│ └────────┘ └────────┘ └────────┘ │
│ Replica 1 Replica 2 Replica 3 │
└─────────────────────────────────────────┘
Traffic Flow
Incoming Requests
Internet
│
├─ HTTP (port 80)
│ └─► haloyd → Redirects to HTTPS
│
└─ HTTPS (port 443)
└─► haloyd
├─ SSL Termination
├─ Domain Routing (my-app.com → my-app)
└─► Load Balance
├─► App Container 1 (port 8080)
├─► App Container 2 (port 8080)
└─► App Container 3 (port 8080)
Internet
│
├─ HTTP (port 80)
│ └─► haloyd → Redirects to HTTPS
│
└─ HTTPS (port 443)
└─► haloyd
├─ SSL Termination
├─ Domain Routing (my-app.com → my-app)
└─► Load Balance
├─► App Container 1 (port 8080)
├─► App Container 2 (port 8080)
└─► App Container 3 (port 8080)
Deployment Flow
Developer: haloy deploy
│
└─► Build image locally (if configured)
│
└─► Upload to server or push to registry
│
└─► API call to haloyd
│
├─► haloyd pulls/loads image
├─► haloyd starts new containers
├─► haloyd waits for health checks
├─► haloyd updates proxy routes
└─► haloyd stops old containers
Developer: haloy deploy
│
└─► Build image locally (if configured)
│
└─► Upload to server or push to registry
│
└─► API call to haloyd
│
├─► haloyd pulls/loads image
├─► haloyd starts new containers
├─► haloyd waits for health checks
├─► haloyd updates proxy routes
└─► haloyd stops old containers
Service Discovery
Haloy uses Docker labels for service discovery. You can leverage this feature in two ways:
- Via Haloy CLI - Deploy using
haloy deploy(recommended) - Direct container labels - Start containers manually with appropriate labels
Using Haloy CLI
The standard approach is to use haloy deploy which handles labeling automatically based on your configuration.
Using Container Labels Directly
You can start containers manually (using docker run, Docker Compose, or other orchestration tools) and haloyd will automatically discover and route traffic to them:
# Start a container with Haloy labels
docker run -d \
--name my-app \
--network haloy \
--label dev.haloy.appName=my-app \
--label dev.haloy.deployment-id=manual-001 \
--label dev.haloy.role=app \
--label dev.haloy.domain.0=example.com \
--label dev.haloy.domain.0.alias.0=www.example.com \
--label dev.haloy.port=8080 \
--label dev.haloy.health-check-path=/health \
my-image:latest
# Start a container with Haloy labels
docker run -d \
--name my-app \
--network haloy \
--label dev.haloy.appName=my-app \
--label dev.haloy.deployment-id=manual-001 \
--label dev.haloy.role=app \
--label dev.haloy.domain.0=example.com \
--label dev.haloy.domain.0.alias.0=www.example.com \
--label dev.haloy.port=8080 \
--label dev.haloy.health-check-path=/health \
my-image:latest
# Docker Compose example
services:
my-app:
image: my-image:latest
networks:
- haloy
labels:
dev.haloy.appName: my-app
dev.haloy.deployment-id: manual-001 # Make sure to increment this manually for the changes to take effect
dev.haloy.role: app
dev.haloy.domain.0: example.com
dev.haloy.domain.0.alias.0: www.example.com
dev.haloy.port: "8080"
dev.haloy.health-check-path: /health
networks:
haloy:
external: true
# Docker Compose example
services:
my-app:
image: my-image:latest
networks:
- haloy
labels:
dev.haloy.appName: my-app
dev.haloy.deployment-id: manual-001 # Make sure to increment this manually for the changes to take effect
dev.haloy.role: app
dev.haloy.domain.0: example.com
dev.haloy.domain.0.alias.0: www.example.com
dev.haloy.port: "8080"
dev.haloy.health-check-path: /health
networks:
haloy:
external: true
Required labels:
dev.haloy.appName- Application identifierdev.haloy.deployment-id- Unique deployment identifierdev.haloy.role- Must be set toappdev.haloy.domain.0- Primary domain (use.1,.2for additional domains)
Optional labels:
dev.haloy.port- Container port (default:8080)dev.haloy.health-check-path- Health check endpoint (default:/)dev.haloy.domain.0.alias.0- Domain alias (use.1,.2for additional aliases)
Discovery Process:
haloydmonitors Docker for labeled containers- Extracts routing information from labels
- Updates proxy routes atomically
- Routes traffic with zero downtime
This allows you to integrate Haloy’s routing and SSL management with your existing deployment workflows.
Networking
Docker Networks
Haloy creates and uses Docker networks:
- haloy (default): Application containers connect to this network
- Custom networks: Via
networkconfiguration option
Port Mapping
haloyd:
- 80:80 (HTTP)
- 443:443 (HTTPS)
Application Containers:
- No direct port exposure
- Internal network only
- haloyd routes traffic
haloyd:
- 80:80 (HTTP)
- 443:443 (HTTPS)
Application Containers:
- No direct port exposure
- Internal network only
- haloyd routes traffic
Data Storage
/etc/haloy/
├── haloyd.yaml # Daemon configuration
└── .env # API tokens
/var/lib/haloy/
├── certs/ # SSL certificates
└── db/ # Deployment database
/etc/haloy/
├── haloyd.yaml # Daemon configuration
└── .env # API tokens
/var/lib/haloy/
├── certs/ # SSL certificates
└── db/ # Deployment database
SSL/TLS Certificates
Certificate Management:
- Automatic via ACME (Let’s Encrypt)
- Certificates stored in
certs/ - Auto-renewal before expiration
- Per-domain certificates
- SNI-based certificate selection with wildcard support
Process:
- Domain configured in
haloy.yaml haloydrequests certificate from Let’s Encrypt- ACME challenge validation (HTTP-01)
- Certificate issued and stored
- Certificate hot-reloaded without restart
- Auto-renewal 30 days before expiration
Health Checks
Haloy includes a unified health checking system with configurable monitoring:
Flow:
haloyd → Health Check → App Container (/health endpoint)
│ │
│ ├─ 200 OK → Healthy
│ └─ Other → Unhealthy
│
└─ Routes traffic only to healthy containers
haloyd → Health Check → App Container (/health endpoint)
│ │
│ ├─ 200 OK → Healthy
│ └─ Other → Unhealthy
│
└─ Routes traffic only to healthy containers
Configuration (in haloyd.yaml):
health_monitor:
enabled: true
interval: "15s" # Check every 15 seconds
fall: 3 # Mark unhealthy after 3 consecutive failures
rise: 2 # Mark healthy after 2 consecutive successes
timeout: "5s" # Per-check timeout
health_monitor:
enabled: true
interval: "15s" # Check every 15 seconds
fall: 3 # Mark unhealthy after 3 consecutive failures
rise: 2 # Mark healthy after 2 consecutive successes
timeout: "5s" # Per-check timeout
Key Features:
- Fall/Rise thresholds: Prevents flapping by requiring consecutive failures/successes
- Concurrent checks: Health checks run in parallel with configurable concurrency
- Automatic route updates: Unhealthy backends are excluded from routing while routes remain active
Actions on Failure:
- Container marked unhealthy after configured failures (fall threshold)
- Traffic stops routing to container
- Container visible in
haloy statusas unhealthy - Container marked healthy again after configured successes (rise threshold)
High Availability
Haloy achieves HA through:
- Multiple replicas: Run 3+ instances
- Health monitoring: Remove unhealthy containers from rotation
- Rolling deployments: Update without downtime
- Load balancing: Distribute traffic evenly
- Automatic recovery: Restart failed containers
Deployment Strategies
Rolling Deployment
Old containers: [1] [2] [3]
│ │ │
Step 1: │ │ │ New [1] starts
Step 2: │ │ │ New [1] healthy → Old [1] stops
Step 3: │ │ │ New [2] starts
Step 4: │ │ │ New [2] healthy → Old [2] stops
Step 5: │ │ │ New [3] starts
Step 6: │ │ │ New [3] healthy → Old [3] stops
▼ ▼ ▼
New containers: [1] [2] [3]
Old containers: [1] [2] [3]
│ │ │
Step 1: │ │ │ New [1] starts
Step 2: │ │ │ New [1] healthy → Old [1] stops
Step 3: │ │ │ New [2] starts
Step 4: │ │ │ New [2] healthy → Old [2] stops
Step 5: │ │ │ New [3] starts
Step 6: │ │ │ New [3] healthy → Old [3] stops
▼ ▼ ▼
New containers: [1] [2] [3]
Replace Deployment
Old containers: [1] [2] [3]
│ │ │
Step 1: Stop all old containers
Step 2: Start all new containers
Step 3: Wait for health checks
▼ ▼ ▼
New containers: [1] [2] [3]
Old containers: [1] [2] [3]
│ │ │
Step 1: Stop all old containers
Step 2: Start all new containers
Step 3: Wait for health checks
▼ ▼ ▼
New containers: [1] [2] [3]
Security
API Authentication:
- API tokens generated during
haloyd init - Tokens stored securely with restrictive permissions
- HTTPS for all API communication (when domain configured)
Systemd Sandboxing:
- Dedicated
haloysystem user NoNewPrivileges=truePrivateTmp=true,ProtectHome=true,ProtectSystem=strictCapabilityBoundingSet=CAP_NET_BIND_SERVICE(allows binding ports 80/443)- Kernel and control group protection
Container Isolation:
- Docker network isolation
- No direct container exposure to internet
- All traffic through haloyd proxy
SSL/TLS:
- Automatic certificate management
- Strong cipher suites
- HTTP to HTTPS redirect
Scalability
Horizontal Scaling:
- Add more replicas in configuration
- Load balanced automatically
- Linear scaling for stateless apps
Multi-Server:
- Deploy to multiple servers
- Independent server scaling
- Geographic distribution
Monitoring
Built-in Monitoring:
- Container health checks with fall/rise thresholds
- Deployment status tracking
- Application container logs via
haloy logs - Platform operational logs via
haloy server logs - Service status via
haloy status - Installation verification via
haloyd verify
External Monitoring:
- Expose health check endpoints
- Monitor via Prometheus/Grafana
- Alert on health check failures
Limitations
- Single server orchestration: Each server managed independently
- No automatic scaling: Manual replica configuration
- No built-in monitoring dashboard: Use external tools
- Docker required: Application containers run in Docker
- Linux only: Server must be Linux-based