Architecture

Understand how Haloy’s components work together to manage your deployments.

System Components

Haloy consists of several components working in harmony:

  1. Haloy CLI (haloy) - Command-line interface for deployments from your local machine
  2. Haloy Daemon (haloyd) - Service running on your server that handles orchestration, routing, and SSL
  3. 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 haloyd API
  • 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 │ └─────────────────────────────────────────┘

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)

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

Service Discovery

Haloy uses Docker labels for service discovery. You can leverage this feature in two ways:

  1. Via Haloy CLI - Deploy using haloy deploy (recommended)
  2. 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
# 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 identifier
  • dev.haloy.deployment-id - Unique deployment identifier
  • dev.haloy.role - Must be set to app
  • dev.haloy.domain.0 - Primary domain (use .1, .2 for 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, .2 for additional aliases)

Discovery Process:

  1. haloyd monitors Docker for labeled containers
  2. Extracts routing information from labels
  3. Updates proxy routes atomically
  4. 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 network configuration option

Port Mapping

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

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:

  1. Domain configured in haloy.yaml
  2. haloyd requests certificate from Let’s Encrypt
  3. ACME challenge validation (HTTP-01)
  4. Certificate issued and stored
  5. Certificate hot-reloaded without restart
  6. 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

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

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 status as unhealthy
  • Container marked healthy again after configured successes (rise threshold)

High Availability

Haloy achieves HA through:

  1. Multiple replicas: Run 3+ instances
  2. Health monitoring: Remove unhealthy containers from rotation
  3. Rolling deployments: Update without downtime
  4. Load balancing: Distribute traffic evenly
  5. 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]

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]

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 haloy system user
  • NoNewPrivileges=true
  • PrivateTmp=true, ProtectHome=true, ProtectSystem=strict
  • CapabilityBoundingSet=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:

External Monitoring:

  • Expose health check endpoints
  • Monitor via Prometheus/Grafana
  • Alert on health check failures

Limitations

  1. Single server orchestration: Each server managed independently
  2. No automatic scaling: Manual replica configuration
  3. No built-in monitoring dashboard: Use external tools
  4. Docker required: Application containers run in Docker
  5. Linux only: Server must be Linux-based

Next Steps