How to Install and Configure Consul for Service Discovery on RHEL 7

As applications grow beyond a single server, tracking where every service is running — and whether it is healthy — becomes a significant operational challenge. Consul, developed by HashiCorp, is a distributed, highly available service mesh and service discovery tool that solves this problem elegantly. It provides a real-time catalog of services registered across your infrastructure, health checking to remove unhealthy instances automatically, a key/value store for dynamic configuration, and an optional service mesh with mutual TLS. Consul’s DNS interface means that existing applications can discover services without any code changes — they simply resolve a DNS name like web.service.consul. This tutorial guides you through installing and configuring a Consul agent on RHEL 7, registering services, using the KV store, and exploring the basics of Consul Connect.

Prerequisites

  • RHEL 7 server with root or sudo access
  • Internet access to download the Consul binary from HashiCorp releases
  • At least 512 MB of RAM and 1 CPU core
  • Ports 8300, 8301 (TCP/UDP), 8302 (TCP/UDP), 8500, and 8600 (TCP/UDP) available
  • unzip and curl installed
# Install prerequisites
sudo yum install -y curl unzip

# Verify curl is available
curl --version

Step 1: Download and Install the Consul Binary

Consul is distributed as a single self-contained binary. Download the appropriate Linux AMD64 build from HashiCorp’s releases page.

# Set the desired Consul version
CONSUL_VERSION="1.15.4"

# Download Consul
curl -O "https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip"

# Download the SHA256 checksum file for verification
curl -O "https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_SHA256SUMS"

# Verify the downloaded binary
sha256sum -c consul_${CONSUL_VERSION}_SHA256SUMS 
  --ignore-missing 2>&1 | grep consul_${CONSUL_VERSION}_linux_amd64.zip

# Unzip the binary
unzip consul_${CONSUL_VERSION}_linux_amd64.zip

# Move to a system-wide location
sudo mv consul /usr/local/bin/
sudo chmod +x /usr/local/bin/consul

# Verify the installation
consul version
# Output: Consul v1.15.4
#         Revision ...
#         Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol > 2 when speaking to compatible agents)

Step 2: Create the Consul User, Directories, and Configuration

Running Consul as a dedicated non-root user follows the principle of least privilege. Create the user, data directory, and configuration directory.

# Create a system user for Consul (no login shell, no home directory)
sudo useradd --system --home /etc/consul.d 
  --shell /bin/false consul

# Create required directories
sudo mkdir -p /etc/consul.d
sudo mkdir -p /opt/consul

# Set ownership
sudo chown -R consul:consul /etc/consul.d /opt/consul
sudo chmod 750 /etc/consul.d

Now create the main Consul configuration file in HCL format:

sudo tee /etc/consul.d/consul.hcl <<'EOF'
# /etc/consul.d/consul.hcl - Consul agent configuration

datacenter = "dc1"
data_dir   = "/opt/consul"

# Bind to the server's primary IP (replace with your actual IP)
bind_addr  = "192.168.1.10"

# Advertise the same address for cluster communication
advertise_addr = "192.168.1.10"

# Client address: 0.0.0.0 allows web UI and API from anywhere
# In production, restrict this to trusted networks
client_addr = "0.0.0.0"

# For a single-node development/test setup
bootstrap_expect = 1
server           = true

# Enable the web UI
ui_config {
  enabled = true
}

# Log level
log_level = "INFO"

# Node name (defaults to hostname if not set)
node_name = "consul-server-01"

# Retry join for server nodes (list all server IPs in a real cluster)
retry_join = ["192.168.1.10"]

# ACL defaults (disabled for initial setup; enable in production)
acl {
  enabled        = false
  default_policy = "allow"
}
EOF

sudo chown consul:consul /etc/consul.d/consul.hcl
sudo chmod 640 /etc/consul.d/consul.hcl

Step 3: Create a systemd Service Unit

sudo tee /etc/systemd/system/consul.service <<'EOF'
[Unit]
Description=Consul Service Discovery Agent
Documentation=https://www.consul.io/
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
User=consul
Group=consul
ExecStart=/usr/local/bin/consul agent 
  -config-dir=/etc/consul.d/
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable consul
sudo systemctl start consul

# Verify Consul is running
sudo systemctl status consul

Step 4: Testing with consul agent -dev (Development Mode)

For a quick local test without any configuration file, Consul’s -dev mode starts an in-memory single-node cluster. This is useful for exploring the API before committing to a full setup.

# Run in a separate terminal (Ctrl+C to stop)
consul agent -dev -ui -client=0.0.0.0

# In another terminal, verify the agent is running
consul members
# Output:
# Node          Address            Status  Type    Build   Protocol  DC   Segment
# hostname      127.0.0.1:8301     alive   server  1.15.4  2         dc1  <all>

Step 5: Using the Key/Value Store

Consul’s KV store provides dynamic configuration for your services. Any service that can make an HTTP request or use the Consul CLI can read and write configuration values.

# Store a configuration value
consul kv put config/app/database_host "db.internal.example.com"
consul kv put config/app/database_port "5432"
consul kv put config/app/max_connections "100"

# Retrieve a single value
consul kv get config/app/database_host
# Output: db.internal.example.com

# List all keys under a prefix
consul kv get -recurse config/app/

# Get with full metadata (version, modify index, flags)
consul kv get -detailed config/app/database_host

# Delete a key
consul kv delete config/app/max_connections

# Watch for changes to a key (blocks until the key changes)
consul watch -type=key -key=config/app/database_host 
  'echo "Config changed: $(consul kv get config/app/database_host)"'

Step 6: Registering a Service

Services are registered by placing JSON or HCL files in the /etc/consul.d/ directory. Consul monitors these files and the services can be discovered via DNS or the HTTP API.

sudo tee /etc/consul.d/web-service.json <<'EOF'
{
  "service": {
    "name": "web",
    "tags": ["nginx", "production"],
    "port": 80,
    "check": {
      "name": "Web HTTP check",
      "http": "http://localhost:80/health",
      "interval": "10s",
      "timeout": "1s"
    }
  }
}
EOF

sudo chown consul:consul /etc/consul.d/web-service.json

# Reload Consul to pick up the new service definition
consul reload

# Verify the service is registered
consul catalog services
# Output:
# consul
# web

Step 7: Service Discovery via DNS

Consul runs a DNS server on port 8600. Services registered in Consul are resolvable using the .consul domain.

# Query the Consul DNS for the "web" service
dig @127.0.0.1 -p 8600 web.service.consul

# Query with SRV record (returns port as well)
dig @127.0.0.1 -p 8600 web.service.consul SRV

# Query for services with a specific tag
dig @127.0.0.1 -p 8600 production.web.service.consul

# Query the Consul node directly
dig @127.0.0.1 -p 8600 consul-server-01.node.consul

# To integrate with system DNS resolver on RHEL 7,
# configure dnsmasq to forward .consul queries to Consul:
sudo yum install -y dnsmasq
echo "server=/consul/127.0.0.1#8600" | 
  sudo tee /etc/dnsmasq.d/consul.conf
sudo systemctl enable dnsmasq
sudo systemctl start dnsmasq

Step 8: Consul Connect — Service Mesh Basics

Consul Connect provides service-to-service mutual TLS encryption and authorization. It uses sidecar proxies (Envoy or the built-in proxy) to intercept and secure traffic without changing application code.

# Enable Connect in the Consul configuration
sudo tee -a /etc/consul.d/consul.hcl <<'EOF'

connect {
  enabled = true
}
EOF

sudo systemctl restart consul

# Register a service with a Connect sidecar proxy
sudo tee /etc/consul.d/db-service.json <<'EOF'
{
  "service": {
    "name": "db",
    "port": 5432,
    "connect": {
      "sidecar_service": {}
    },
    "check": {
      "tcp": "localhost:5432",
      "interval": "10s"
    }
  }
}
EOF

consul reload

# Start the sidecar proxy for the db service
consul connect proxy 
  -sidecar-for db 
  -log-level INFO &

# Services that want to connect to "db" use an intention:
consul intention create web db

# Verify the intention
consul intention list

Consul transforms the operational complexity of service discovery into a simple, scalable DNS and API interface. By running the Consul agent as a systemd-managed service on each RHEL 7 node, every application gains access to a live service registry with automatic health-check-driven deregistration, a distributed key/value store for runtime configuration, and optionally a service mesh that encrypts all inter-service communication. As your infrastructure grows, Consul clusters scale horizontally with a Raft consensus group of server nodes, while client agents on every host keep service registrations and health checks local, minimizing network overhead. Starting with the configuration in this guide and adding ACL tokens in production will give you a secure, production-ready service discovery foundation.