Install and configure Nomad for container orchestration with Consul integration

Intermediate 25 min Apr 01, 2026 50 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up HashiCorp Nomad cluster with Consul service discovery for production container orchestration. Learn job scheduling, ACL security, TLS encryption, and monitoring deployment.

Prerequisites

  • Root or sudo access
  • Minimum 2GB RAM and 2 CPU cores
  • Docker runtime support
  • Open network ports for cluster communication

What this solves

HashiCorp Nomad provides flexible container orchestration that's simpler than Kubernetes while offering powerful job scheduling and resource management. This tutorial sets up a production-ready Nomad cluster integrated with Consul for service discovery, complete with ACL security and TLS encryption for enterprise environments.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions and install required dependencies.

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget unzip docker.io jq
sudo dnf update -y
sudo dnf install -y curl wget unzip docker jq

Install HashiCorp GPG key and repository

Add the official HashiCorp repository to get the latest Nomad and Consul packages with automatic updates.

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/fedora/hashicorp.repo

Install Nomad and Consul

Install both Nomad for orchestration and Consul for service discovery and cluster coordination.

sudo apt install -y nomad consul
sudo dnf install -y nomad consul

Create system users and directories

Create dedicated users for Nomad and Consul with proper permissions for security isolation.

sudo useradd --system --home /etc/nomad.d --shell /bin/false nomad
sudo useradd --system --home /etc/consul.d --shell /bin/false consul
sudo mkdir -p /opt/nomad/data /opt/consul/data
sudo mkdir -p /etc/nomad.d /etc/consul.d
sudo chown -R nomad:nomad /opt/nomad /etc/nomad.d
sudo chown -R consul:consul /opt/consul /etc/consul.d
sudo chmod 755 /opt/nomad /opt/consul
sudo chmod 750 /etc/nomad.d /etc/consul.d

Enable Docker service

Start and enable Docker for container workload support in Nomad jobs.

sudo systemctl enable --now docker
sudo usermod -aG docker nomad

Generate encryption keys

Create encryption keys for secure cluster communication between Consul and Nomad nodes.

CONSUL_ENCRYPT_KEY=$(consul keygen)
NOMAD_ENCRYPT_KEY=$(nomad operator keygen)
echo "Consul encryption key: $CONSUL_ENCRYPT_KEY"
echo "Nomad encryption key: $NOMAD_ENCRYPT_KEY"
Note: Save these keys securely. You'll need them for all cluster nodes and configuration files.

Configure Consul server

Set up Consul as the service discovery backend with clustering and ACL support.

datacenter = "dc1"
data_dir = "/opt/consul/data"
log_level = "INFO"
server = true
bootstrap_expect = 1
bind_addr = "0.0.0.0"
client_addr = "0.0.0.0"
retry_join = ["127.0.0.1"]
ui_config {
  enabled = true
}
connect {
  enabled = true
}
encrypt = "CONSUL_ENCRYPT_KEY_HERE"
acl = {
  enabled = true
  default_policy = "deny"
  enable_token_persistence = true
}
ports {
  grpc = 8502
}
Important: Replace CONSUL_ENCRYPT_KEY_HERE with the actual encryption key generated in the previous step.

Configure Nomad server

Set up Nomad server with Consul integration, ACLs, and proper resource allocation.

datacenter = "dc1"
data_dir = "/opt/nomad/data"
log_level = "INFO"
bind_addr = "0.0.0.0"
server {
  enabled = true
  bootstrap_expect = 1
  encrypt = "NOMAD_ENCRYPT_KEY_HERE"
}
client {
  enabled = true
  servers = ["127.0.0.1:4647"]
}
consul {
  address = "127.0.0.1:8500"
  server_service_name = "nomad"
  client_service_name = "nomad-client"
  auto_advertise = true
  server_auto_join = true
  client_auto_join = true
}
acl {
  enabled = true
}
plugin "docker" {
  config {
    allow_privileged = false
    allow_caps = ["audit_write", "chown", "dac_override", "fowner", "fsetid", "kill", "mknod", "net_bind_service", "setfcap", "setgid", "setpcap", "setuid", "sys_chroot"]
  }
}
telemetry {
  collection_interval = "1s"
  disable_hostname = true
  prometheus_metrics = true
  publish_allocation_metrics = true
  publish_node_metrics = true
}
Important: Replace NOMAD_ENCRYPT_KEY_HERE with the actual Nomad encryption key generated earlier.

Set proper file permissions

Secure configuration files with correct ownership and minimal permissions to prevent unauthorized access.

sudo chown consul:consul /etc/consul.d/consul.hcl
sudo chown nomad:nomad /etc/nomad.d/nomad.hcl
sudo chmod 640 /etc/consul.d/consul.hcl
sudo chmod 640 /etc/nomad.d/nomad.hcl
Never use chmod 777. Configuration files contain sensitive encryption keys and should only be readable by the service user and root.

Start and enable services

Start Consul first, then Nomad, as Nomad depends on Consul for service discovery.

sudo systemctl enable --now consul
sudo systemctl enable --now nomad
sudo systemctl status consul
sudo systemctl status nomad

Bootstrap Consul ACLs

Initialize the Consul ACL system and create management tokens for secure access control.

sleep 10
consul acl bootstrap > /tmp/consul-bootstrap.txt
CONSUL_MASTER_TOKEN=$(grep "SecretID:" /tmp/consul-bootstrap.txt | awk '{print $2}')
echo "Consul Master Token: $CONSUL_MASTER_TOKEN"
export CONSUL_HTTP_TOKEN=$CONSUL_MASTER_TOKEN
Note: Save the master token securely. This provides full administrative access to your Consul cluster.

Configure Nomad ACL integration

Create a Consul policy and token for Nomad to access Consul services securely.

consul acl policy create -name "nomad-server" -description "Nomad server policy" -rules '
node_prefix "" {
  policy = "read"
}
service_prefix "" {
  policy = "write"
}
agent_prefix "" {
  policy = "read"
}'
consul acl token create -description "Nomad server token" -policy-name "nomad-server" > /tmp/nomad-consul-token.txt
NOMAD_CONSUL_TOKEN=$(grep "SecretID:" /tmp/nomad-consul-token.txt | awk '{print $2}')
echo "Nomad Consul Token: $NOMAD_CONSUL_TOKEN"

Update Nomad configuration with Consul token

Add the Consul token to Nomad configuration for authenticated service registration.

sudo sed -i '/consul {/a\  token = "'$NOMAD_CONSUL_TOKEN'"' /etc/nomad.d/nomad.hcl
sudo systemctl restart nomad

Bootstrap Nomad ACLs

Initialize Nomad's ACL system and create management tokens for job scheduling permissions.

sleep 5
nomad acl bootstrap > /tmp/nomad-bootstrap.txt
NOMAD_MASTER_TOKEN=$(grep "Secret ID" /tmp/nomad-bootstrap.txt | awk '{print $4}')
echo "Nomad Master Token: $NOMAD_MASTER_TOKEN"
export NOMAD_TOKEN=$NOMAD_MASTER_TOKEN

Deploy a sample web application

Create and run a simple Nginx job to test the cluster functionality and service registration.

job "nginx" {
  datacenters = ["dc1"]
  type = "service"
  
  group "web" {
    count = 2
    
    network {
      port "http" {
        static = 8080
      }
    }
    
    service {
      name = "nginx"
      port = "http"
      
      check {
        type = "http"
        path = "/"
        interval = "10s"
        timeout = "2s"
      }
    }
    
    task "nginx" {
      driver = "docker"
      
      config {
        image = "nginx:alpine"
        ports = ["http"]
      }
      
      resources {
        cpu = 100
        memory = 128
      }
    }
  }
}
nomad job run /tmp/nginx-job.nomad

Configure firewall rules

Open necessary ports for Nomad and Consul communication between cluster nodes.

sudo ufw allow 4646/tcp comment 'Nomad HTTP'
sudo ufw allow 4647/tcp comment 'Nomad RPC'
sudo ufw allow 4648/tcp comment 'Nomad Serf'
sudo ufw allow 8500/tcp comment 'Consul HTTP'
sudo ufw allow 8501/tcp comment 'Consul HTTPS'
sudo ufw allow 8502/tcp comment 'Consul gRPC'
sudo ufw allow 8300/tcp comment 'Consul server RPC'
sudo ufw allow 8301/tcp comment 'Consul Serf LAN'
sudo ufw allow 8302/tcp comment 'Consul Serf WAN'
sudo ufw allow 8080/tcp comment 'Nginx demo app'
sudo ufw reload
sudo firewall-cmd --permanent --add-port=4646/tcp --add-port=4647/tcp --add-port=4648/tcp
sudo firewall-cmd --permanent --add-port=8500/tcp --add-port=8501/tcp --add-port=8502/tcp
sudo firewall-cmd --permanent --add-port=8300/tcp --add-port=8301/tcp --add-port=8302/tcp
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload

Verify your setup

Check that all services are running and the cluster is healthy with proper service registration.

systemctl status consul nomad
nomad server members
nomad node status
nomad job status nginx
consul members
consul catalog services
curl -s http://localhost:8500/v1/health/service/nginx | jq .
curl -I http://localhost:8080
Web Interfaces: Access Consul UI at http://your-server-ip:8500 and Nomad UI at http://your-server-ip:4646 using your respective master tokens.

Common issues

SymptomCauseFix
Nomad can't connect to ConsulConsul ACL token missingAdd token to nomad.hcl consul block and restart
Jobs fail to startDocker permission deniedsudo usermod -aG docker nomad && sudo systemctl restart nomad
Service discovery not workingConsul integration disabledCheck consul block in nomad.hcl has auto_advertise = true
ACL permission deniedInvalid or expired tokensUse export NOMAD_TOKEN=your-token and export CONSUL_HTTP_TOKEN=your-token
Port allocation failuresPorts already in useUse dynamic ports or check netstat -tlnp for conflicts
TLS certificate errorsClock skew between nodesSync time with sudo ntpdate -s time.nist.gov

Next steps

Automated install script

Run this to automate the entire setup

#hashicorp-nomad #nomad-cluster #container-orchestration #nomad-consul #job-scheduling

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer