Configuration Reference

Complete reference for all Haloy configuration options.

Configuration Structure

The configuration file supports two modes of operation:

  1. Single Deployment: If no targets are defined, the root configuration acts as the single deployment target.
  2. Multi-Target: If targets are defined, the root configuration acts as the Base/Default configuration. Specific targets inherit these defaults and can override them.

Single Deployment Example

name: "my-app" server: "haloy.yourserver.com" image: repository: "my-app" tag: "latest"

Multi-Target Example

# Base settings inherited by all targets image: repository: "my-app" tag: "latest" targets: prod: server: "prod.server.com" replicas: 2 staging: server: "staging.server.com" replicas: 1

Global Configuration

These options are only available at the top level of the configuration file.

KeyTypeDescription
targetsobjectDefine multiple deployment targets (see Multi-Server Deployments)
imagesmapDefine named images that can be referenced by targets
secret_providersobjectConfigure secret providers (see Secret Providers)
global_pre_deployarrayCommands to run once before any deployment starts
global_post_deployarrayCommands to run once after all deployments finish

Target Configuration

These options define a deployment unit.

  • At Root: They serve as the default settings (or the single deployment configuration).
  • Under targets: They override the defaults for that specific target.
KeyTypeRequiredDescription
namestringConditionalApplication name. (see Container Name Source)
presetstringNoApply preset configuration (Options: database, service) (see Presets)
protectedbooleanNoExclude from --all deployments (default: false) (see Protected Targets)
naming_strategystringNoContainer naming: “dynamiAc” (default) or “static” (see Naming Strategy)
imageobjectNoDocker image configuration (see Image Configuration)
serverstringNoHaloy server API URL
api_tokenobjectNoAPI token configuration (see Authentication)
deployment_strategystringNoDeployment strategy: “rolling” (default) or “replace”
domainsarrayNoDomain configuration
acme_emailstringNoLet’s Encrypt email (required with domains)
replicasintegerNoNumber of container instances (default: 1)
portstring/integerNoContainer port to expose (default: “8080”). The port your application listens on inside the container.
health_check_pathstringNoHealth check endpoint (default: ”/“)
envarrayNoEnvironment variables (see Environment Variables)
volumesarrayNoVolume mounts (see Volumes)
pre_deployarrayNoCommands to run before deploy (per target)
post_deployarrayNoCommands to run after deploy (per target)
networkstringNoDocker network for the container. (default: haloy)

Configuration File Discovery

Haloy automatically searches for configuration files in the current directory in this order:

  1. haloy.yaml
  2. haloy.yml
  3. haloy.json
  4. haloy.toml

Specify a custom location:

# Specific file haloy deploy --config /path/to/config.yaml # Directory (will search for config files inside) haloy deploy --config /path/to/directory

Most Haloy commands require a configuration file. See Basic Configuration to get started.

Presets

Apply sensible defaults for specific use cases using the preset option.

Database Preset

Use preset: "database" for stateful database services. This automatically applies:

  • deployment_strategy: "replace" (safer for databases)
  • naming_strategy: "static" (predictable container names)
  • protected: true (prevents accidental deployment)
  • image.history.strategy: "none" (no rollback history)
postgres: preset: database image: repository: postgres tag: "18" volumes: - /data/postgres:/var/lib/postgresql/data

Service Preset

Use preset: "service" for stateful services that share similar requirements to databases (static naming, replace strategy) but do not need the strict safety of being protected. This automatically applies:

  • deployment_strategy: "replace"
  • naming_strategy: "static"
  • image.history.strategy: "none"
redis: preset: service image: repository: "henrygd/beszel" tag: "latest"

Protected Targets

Prevent accidental deployment of critical services (like databases) by marking them as protected.

targets: postgres: protected: true
  • Skipped by default when using haloy deploy --all
  • Deploy explicitly: haloy deploy -t postgres
  • Force inclusion: haloy deploy --all --include-protected

Container Name Source

  • Single-target configs: Container names are derived from the root name field (required).
  • Multi-target configs: Container names are derived from the target key by default. Targets can explicitly set name to override this.

Example (multi-target):

targets: production: # Container: production-abc123 server: prod.server.com staging: # Container: staging-abc123 server: staging.server.com

Constraints for Static Naming:

  • Requires deployment_strategy: "replace"
  • Does not support multiple replicas
naming_strategy: static deployment_strategy: replace

Naming Strategy

Control how container names are generated.

StrategyDescriptionExample
dynamic (default)Includes deployment IDmyapp-abc123
staticUses app name onlymyapp

Constraints for Static Naming:

  • Requires deployment_strategy: "replace"
  • Does not support multiple replicas
name: postgres naming_strategy: static deployment_strategy: replace

Deployment Strategies

Rolling Deployment (Default)

Gradually replaces old containers with new ones, ensuring zero downtime:

name: "my-app" deployment_strategy: "rolling" replicas: 3

Replace Deployment

Stops all old containers before starting new ones:

name: "my-app" deployment_strategy: "replace" replicas: 3

Deployment Hooks

Important: All deployment hooks (pre_deploy, post_deploy, global_pre_deploy, and global_post_deploy) are executed by the haloy CLI tool on the machine where you run the deployment command, not on the server. This means:

  • Hooks run in your local environment with access to your local filesystem, environment variables, and installed tools
  • They do not have direct access to the server’s filesystem or environment
  • Use hooks for local preparation tasks like building assets, running tests, or sending notifications
  • For server-side operations, consider using container initialization scripts or application startup logic

Run custom commands before or after deployment:

name: "my-app" pre_deploy: - "npm run migrate" - "echo 'Starting deployment'" post_deploy: - "curl -X POST https://status.example.com/notify" - "echo 'Deployment complete'"

For multi-target deployments, use global hooks:

global_pre_deploy: - "npm run build" - "docker build -t my-app ." global_post_deploy: - "echo 'All deployments complete'" targets: production: server: prod.haloy.com pre_deploy: - "npm run test:production" staging: server: staging.haloy.com pre_deploy: - "npm run test:staging"

Multi-Target Overrides

When using multi-target deployments, each target can override base configuration:

KeyTypeDescription
serverstringOverride the server for this target
api_tokenobjectOverride the API token configuration
imageobjectOverride image configuration (repository, tag, etc.)
domainsarrayOverride domain configuration
acme_emailstringOverride ACME email
envarrayOverride environment variables
replicasintegerOverride number of replicas
presetstringOverride preset
protectedbooleanOverride protected status
naming_strategystringOverride naming strategy
deployment_strategystringOverride deployment strategy
portstringOverride container port
health_check_pathstringOverride health check path
volumesarrayOverride volume mounts
pre_deployarrayOverride pre-deploy hooks
post_deployarrayOverride post-deploy hooks
networkstringOverride docker network

Inheritance Rules:

  • Base configuration provides defaults for all targets
  • Most target-specific values completely override base values (no merging)
  • Only specified fields in targets override the base
  • Exception: Environment variables (env) are merged - target values override base values with the same name, while preserving other base variables
  • global_pre_deploy and global_post_deploy run once regardless of targets

Example

# Base configuration - inherited by all targets image: repository: "ghcr.io/my-org/my-app" tag: "latest" replicas: 2 port: "8080" env: - name: "LOG_LEVEL" value: "info" # Targets targets: production: # Inherits: replicas=2, port="8080", base env (LOG_LEVEL) # Overrides: image.tag, adds domains, adds/overrides env variables server: "prod.haloy.com" image: tag: "v1.2.3" domains: - domain: "my-app.com" env: # Merges with base env - name: "NODE_ENV" value: "production" # LOG_LEVEL="info" is inherited from base staging: # Inherits: image (repository + tag), replicas=2, port="8080", base env # Overrides: server, changes replicas, adds domains, overrides LOG_LEVEL server: "staging.haloy.com" replicas: 1 domains: - domain: "staging.my-app.com" env: - name: "LOG_LEVEL" value: "debug" # FEATURE_FLAG is inherited from base

Custom Docker Network

By default, containers are attached to the haloy network. You can override this:

name: "my-app" network: "my-custom-network"

Important: If you override the default network (haloy), the Haloy proxy will not be able to discover your containers. This means:

  • Your application containers will not be included in the HAProxy configuration
  • Traffic will not be routed to your application
  • Your domains will not work, even though the containers are running
  • The containers will be completely ignored by the routing system after they start

Only change the network if you have a specific networking requirement and understand that you’ll need to handle routing separately.

Validation

Validate your configuration file:

haloy validate-config haloy validate-config --config path/to/config.yaml haloy validate-config --show-resolved-config # Display with secrets (use with caution)

Next Steps