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: "my-app:latest"

Multi-Target Example

# Base settings inherited by all targets image: "my-app: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. Values can be strings or objects.
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

Secret Providers

secret_providers defines reusable secret sources for from.secret references. Haloy currently supports onepassword and sops, and secret references use the provider:source:key format.

secret_providers: onepassword: production-db: vault: "Production" item: "Database Credentials" sops: production: file: "./secrets.production.yaml" env: - name: "DB_PASSWORD" from: secret: "onepassword:production-db:password" - name: "API_SECRET" from: secret: "sops:production:api.secret"

1Password sources support account (optional), vault, and item. SOPS sources support file and optional format (yaml, json, or dotenv). SOPS file paths are resolved relative to the Haloy config file.

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: “dynamic” (default) or “static” (see Naming Strategy)
imagestring/objectNoDocker image configuration. A string is shorthand for repository. When omitted or partially specified, repository defaults to the target/app name. (see Image Configuration)
image_keystringNoReference a named image from the top-level images map. Cannot be used together with image.
serverstringNoHaloy server API URL
api_tokenobjectNoAPI token configuration (see Authentication)
deployment_strategystringNoDeployment strategy: “rolling” (default) or “replace”
domainsarrayNoDomain configuration
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: ”/“)
min_ready_secondsintegerNoMinimum stabilization time after a container becomes healthy before it is considered ready (default: 0)
envarrayNoEnvironment variables. Supports ${VAR_NAME} interpolation in value: strings (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)

Readiness Stabilization

Use min_ready_seconds to require a container to stay healthy for a minimum period after it first passes health checks. This helps catch containers that start successfully and then crash a few seconds later.

name: "my-app" health_check_path: "/health" min_ready_seconds: 10
  • Default: 0 (disabled)
  • Valid range: 0 to 600
  • YAML/TOML field name: min_ready_seconds
  • JSON field name: minReadySeconds

Haloy measures this window from the container start time. If the container has already been running long enough when health checks pass, it becomes ready immediately. Otherwise Haloy waits the remaining time and re-checks the container state before finishing the deployment.

Multi-Target Inheritance

Like other target settings, min_ready_seconds can be defined at the root and overridden per target:

min_ready_seconds: 5 targets: web: server: "prod.haloy.com" image: "nginx:latest" domains: - domain: "app.example.com" api: server: "api.haloy.com" image: "node:20" min_ready_seconds: 15 domains: - domain: "api.example.com"

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: "postgres:18" volumes: - /data/postgres:/var/lib/postgresql/data

For practical multi-database and backup examples, see Databases.

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: "henrygd/beszel: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
imagestring/objectOverride image configuration (repository, tag, etc.)
image_keystringSelect a named image from top-level images
domainsarrayOverride domain configuration
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
min_ready_secondsintegerOverride readiness stabilization time
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 proxy routing
  • 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

Stay updated on Haloy

Get notified about new docs, deployment patterns, and Haloy updates.