Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Consul Ubuntu
GUIDEInstall Guides

How to Install HashiCorp Consul on Ubuntu 24.04 VPS: Service Discovery, KV, Connect Mesh

28 min read

How to Install HashiCorp Consul on Ubuntu 24.04 VPS: Service Discovery, KV, Connect Mesh

HashiCorp Consul is the Swiss Army knife of modern infrastructure. In one binary it gives you service discovery, a distributed key-value store, health checking, multi-datacentre networking, and a full service mesh with mTLS — the same toolkit that runs inside Shopify, Cloudflare, Roblox, and thousands of other production stacks. This guide walks you through installing Consul on Ubuntu 24.04 from the official HashiCorp apt repository, configuring a 3-node highly available cluster, bootstrapping ACLs, encrypting gossip and RPC traffic with TLS, and bringing up Consul Connect with sidecar proxies so your services can talk to each other over authenticated mTLS without changing a line of application code.

Prefer less yak-shaving? Deploy Consul on our CloudCore Professional plan and have a hardened 3-node cluster running in under 15 minutes.

Table of Contents

  • What is HashiCorp Consul?
  • Why Self-Host Consul?
  • Prerequisites
  • Step 1: Prepare All Nodes
  • Step 2: Add the HashiCorp APT Repository
  • Step 3: Install the Consul Package
  • Step 4: Generate a Gossip Encryption Key
  • Step 5: Write the consul.hcl Configuration
  • Step 6: Start the Systemd Service
  • Step 7: Bootstrap the ACL System
  • Step 8: Enable TLS for RPC and HTTPS
  • Step 9: Register a Service and Add Health Checks
  • Step 10: Use the KV Store
  • Step 11: Enable Consul Connect Service Mesh
  • Step 12: Resolve Services via DNS
  • Step 13: Access the Web UI
  • Single-Server Dev Mode
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is HashiCorp Consul?

    Consul is an open-source networking platform originally released by HashiCorp in 2014. Under the hood it is a distributed system built on the Raft consensus protocol (for strongly consistent state) and the Serf gossip protocol (for cluster membership and failure detection). On top of those primitives it exposes five user-facing products that most teams adopt incrementally:

    • Service discovery. Services register themselves with Consul and clients look them up by name instead of IP. A crashed node is detected by its peers within seconds, and traffic stops being routed to it automatically.
    • Health checking. Each registered service can have HTTP, TCP, gRPC, script, or TTL-based health checks. Failing services are removed from service discovery results without any operator action.
    • Key-value store. A strongly consistent hierarchical KV database (similar to etcd) used for feature flags, dynamic configuration, leader election, and distributed locking.
    • Multi-datacentre federation. A single Consul deployment can span multiple regions with WAN gossip, giving you cross-region service discovery without stretching a single Raft cluster across high-latency links.
    • Consul Connect. A built-in service mesh that issues short-lived x509 certificates to each service and routes east-west traffic through sidecar proxies. Authorisation rules (called intentions) decide which services may call which — with zero application changes.
    Consul runs as a single Go binary. Every node in your infrastructure runs a Consul agent, which is either a server (participates in Raft, stores state) or a client (stateless, forwards requests to servers). A typical production deployment has 3 or 5 servers in a cluster for high availability, and one client agent on every application node.

    Why Self-Host Consul?

    You could reach for AWS Cloud Map, Google Cloud Service Directory, or HashiCorp's HCP Consul managed offering. Self-hosting still wins in several situations:

    • Flat, predictable cost. A 3-node Consul cluster on VPS costs roughly EUR 60/month regardless of how many services or KV reads you throw at it. Managed service meshes typically charge per service-hour or per request.
    • No cloud lock-in. Consul runs the same way on Contabo, Hetzner, bare metal, on-prem hypervisors, or a Raspberry Pi cluster. Multi-cloud and hybrid deployments are trivial.
    • Data sovereignty. Your KV store may contain feature flags, secrets (if you pair it with Vault), or tenant metadata. Keeping that on infrastructure you control is often a legal requirement under GDPR, HIPAA, or sector-specific rules.
    • Full feature set. The self-hosted OSS build includes Consul Connect, ACLs, TLS, multi-DC federation, and the HTTP/DNS APIs. You are not gated behind a higher pricing tier to enable production features.
    • Deep integration with Vault and Nomad. Consul, Vault, and Nomad form HashiCorp's self-hostable stack. Running all three on the same nodes gives you secrets management, scheduling, and service mesh for less than the cost of a single managed Kubernetes cluster.
    • Tuning freedom. Adjust Raft snapshot thresholds, gossip timing, ACL cache TTLs, and log levels to match your workload. Managed services expose only a fraction of these knobs.

    Prerequisites

    Before you begin, make sure you have:

    • Three Ubuntu 24.04 LTS VPS instances (for a production cluster). For learning, a single VPS with bootstrap_expect = 1 is fine — skip to Single-Server Dev Mode.
    • Root or sudo access on each node via SSH.
    • Private networking between nodes if possible — Consul gossip is chatty (thousands of packets per minute), and private-network bandwidth is usually free and lower-latency.
    • At least 1 GB RAM and 2 vCPU per server node. Consul itself is light (40-200 MB RAM), but Raft disk fsyncs benefit from NVMe storage. For clients co-located with applications, add 128 MB RAM on top of your app's budget.
    • Unique hostnames for each node (consul-1, consul-2, consul-3 or similar).
    Recommended Plan: CloudCore Professional
    >
    Three CloudCore Professional VPS instances make an ideal Consul cluster:
    >
    - 6 vCPU cores per node
    - 12 GB RAM per node
    - 100 GB NVMe SSD per node (fast Raft writes)
    - Unmetered bandwidth
    - Private networking included
    - EUR 19.99/month per node (EUR 59.97/month for the full cluster)
    >
    That gives plenty of headroom to co-locate Consul servers with Vault, Nomad, or a small application workload.

    Note the private IPs of your three nodes before continuing. The rest of this guide uses the placeholders 10.0.0.11, 10.0.0.12, and 10.0.0.13 — replace them with your actual addresses.

    Step 1: Prepare All Nodes

    Run these commands on every node (consul-1, consul-2, consul-3).

    Update the package index:

    bash
    sudo apt update && sudo apt upgrade -y

    Install prerequisites:

    bash
    sudo apt install -y curl gnupg lsb-release software-properties-common unzip jq

    Set a unique hostname on each node:

    bash
    # On consul-1
    sudo hostnamectl set-hostname consul-1

    On consul-2

    sudo hostnamectl set-hostname consul-2

    On consul-3

    sudo hostnamectl set-hostname consul-3

    Add each node to /etc/hosts on all three machines so they can resolve each other by name:

    bash
    sudo tee -a /etc/hosts > /dev/null <<EOF
    10.0.0.11   consul-1
    10.0.0.12   consul-2
    10.0.0.13   consul-3
    EOF

    Open the required firewall ports between the Consul nodes:

    bash
    sudo ufw allow from 10.0.0.0/24 to any port 8300 proto tcp comment 'Consul server RPC'
    sudo ufw allow from 10.0.0.0/24 to any port 8301 comment 'Consul LAN Serf'
    sudo ufw allow from 10.0.0.0/24 to any port 8302 comment 'Consul WAN Serf'
    sudo ufw allow from 10.0.0.0/24 to any port 8500 proto tcp comment 'Consul HTTP API/UI'
    sudo ufw allow from 10.0.0.0/24 to any port 8501 proto tcp comment 'Consul HTTPS API'
    sudo ufw allow from 10.0.0.0/24 to any port 8600 comment 'Consul DNS'

    Replace 10.0.0.0/24 with the actual subnet your nodes share. Never expose Consul ports to the public internet — always bind them to the private interface.

    Step 2: Add the HashiCorp APT Repository

    HashiCorp publishes signed .deb packages for Consul, Vault, Nomad, Terraform, and other products through a single apt repository. This is the recommended installation method because it keeps Consul updated alongside the rest of your system via standard apt upgrade.

    Run these commands on every node.

    Import HashiCorp's GPG key:

    bash
    wget -O- https://apt.releases.hashicorp.com/gpg | \
      sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

    Add the apt repository:

    bash
    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

    Update the package index:

    bash
    sudo apt update

    Expected output:

    text
    Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
    Get:2 https://apt.releases.hashicorp.com noble InRelease [12.9 kB]
    Get:3 https://apt.releases.hashicorp.com noble/main amd64 Packages [86.3 kB]
    Reading package lists... Done

    Step 3: Install the Consul Package

    Install Consul on all three nodes:

    bash
    sudo apt install -y consul

    Verify the installed version:

    bash
    consul version

    Expected output:

    text
    Consul v1.20.1
    Revision 5b1f0dae
    Build Date 2025-11-05T18:43:32Z
    Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

    The package installs:

    • The consul binary at /usr/bin/consul
    • A dedicated consul system user and group
    • The data directory /opt/consul
    • The config directory /etc/consul.d with a stub consul.hcl
    • A systemd unit at /usr/lib/systemd/system/consul.service
    Do not start the service yet — the default config is not suitable for a cluster. We will rewrite /etc/consul.d/consul.hcl in Step 5.

    Step 4: Generate a Gossip Encryption Key

    Consul agents use the Serf gossip protocol to discover peers and detect failures. Every gossip packet must be encrypted with a shared 32-byte symmetric key, otherwise anyone on the network can inject forged node-joined events or partition the cluster.

    Generate the key once on any node:

    bash
    consul keygen

    Expected output:

    text
    Rj7GfN1qXkT6pVzA0QwLmE8YcBoH3KjD2sUiP4MbNxY=

    Copy this value — you will paste the same key into every node's consul.hcl. Losing it means the cluster cannot rejoin after a restart, so treat it like a password and store it in your secrets manager.

    Step 5: Write the consul.hcl Configuration

    Replace the default config with a cluster-ready configuration. Run this on each node, substituting NODE_NAME, BIND_ADDR, and the shared gossip key.

    Configuration for consul-1

    bash
    sudo tee /etc/consul.d/consul.hcl > /dev/null <<'EOF'
    datacenter        = "dc1"
    data_dir          = "/opt/consul"
    node_name         = "consul-1"
    server            = true
    bootstrap_expect  = 3

    bind_addr = "10.0.0.11" client_addr = "0.0.0.0" advertise_addr = "10.0.0.11"

    retry_join = ["10.0.0.11", "10.0.0.12", "10.0.0.13"]

    encrypt = "Rj7GfN1qXkT6pVzA0QwLmE8YcBoH3KjD2sUiP4MbNxY="

    ui_config { enabled = true }

    connect { enabled = true }

    ports { grpc = 8502 grpc_tls = 8503 }

    acl { enabled = true default_policy = "deny" enable_token_persistence = true }

    log_level = "INFO" log_file = "/var/log/consul/" EOF

    Repeat on consul-2 (change node_name, bind_addr, and advertise_addr to the second node's values) and on consul-3.

    What each directive does

    • datacenter — Logical grouping name. A single Consul cluster lives in one datacentre; multi-DC federation connects several datacenters.
    • data_dir — Where Raft logs, snapshots, and persisted state live. Must be on persistent disk — do not point this at /tmp.
    • server = true — This node participates in Raft. Clients would set server = false.
    • bootstrap_expect = 3 — Wait for 3 servers to be available before electing a leader. For a single-server dev cluster set this to 1. Never set it to 2 — you would have no failure tolerance.
    • bind_addr — The private interface Consul binds all its ports to.
    • client_addr = "0.0.0.0" — Interface for the HTTP API, UI, and DNS. 0.0.0.0 is fine here because UFW already restricts access.
    • retry_join — List of peers to try contacting on startup. Unlike join, this retries forever — safe to list nodes that boot out of order.
    • encrypt — The gossip key from Step 4. Must be identical on every node.
    • ui_config.enabled — Serves the Consul web UI at http://<node>:8500.
    • connect.enabled — Turns on the Connect CA and service mesh certificate issuance.
    • ports.grpc — Required for Envoy sidecar proxies used by Connect.
    • acl.default_policy = "deny" — The secure default. Without a valid token, the API returns 403. We bootstrap ACLs in Step 7.

    Secure file permissions

    The gossip key is sensitive:

    bash
    sudo chown -R consul:consul /etc/consul.d /opt/consul
    sudo chmod 640 /etc/consul.d/consul.hcl

    Create and own the log directory:

    bash
    sudo mkdir -p /var/log/consul
    sudo chown consul:consul /var/log/consul

    Validate the config before starting:

    bash
    sudo -u consul consul validate /etc/consul.d/

    Expected output:

    text
    Configuration is valid!

    Step 6: Start the Systemd Service

    Enable and start Consul on all three nodes (run the commands in parallel across terminals so they boot close together — this helps the initial leader election):

    bash
    sudo systemctl enable --now consul

    Check status:

    bash
    sudo systemctl status consul

    Expected output:

    text
    ● consul.service - "HashiCorp Consul - A service mesh solution"
         Loaded: loaded (/usr/lib/systemd/system/consul.service; enabled; preset: enabled)
         Active: active (running) since Thu 2026-04-16 10:15:21 UTC; 10s ago
       Main PID: 1321 (consul)
          Tasks: 14 (limit: 14236)
         Memory: 62.4M
         CGroup: /system.slice/consul.service
                 └─1321 /usr/bin/consul agent -config-dir=/etc/consul.d/

    Watch the logs for a successful leader election:

    bash
    sudo journalctl -u consul -f

    Look for a line like:

    text
    [INFO]  agent.server.raft: entering leader state: leader="Node at 10.0.0.11:8300 [Leader]"
    [INFO]  agent: Synced node info

    Confirm cluster membership from any node:

    bash
    consul members

    Expected output:

    text
    Node      Address          Status  Type    Build   Protocol  DC   Partition  Segment
    consul-1  10.0.0.11:8301   alive   server  1.20.1  2         dc1  default    <all>
    consul-2  10.0.0.12:8301   alive   server  1.20.1  2         dc1  default    <all>
    consul-3  10.0.0.13:8301   alive   server  1.20.1  2         dc1  default    <all>

    Three nodes, all alive, all server — you have a healthy cluster.

    Step 7: Bootstrap the ACL System

    With default_policy = "deny" the cluster is locked down, but no tokens exist yet. The bootstrap command creates the first management token that can create every other token.

    Run on the leader (any server works):

    bash
    consul acl bootstrap

    Expected output:

    text
    AccessorID:       b3c6c64f-1f9a-4d9c-9e90-d9b5f44c6d1f
    SecretID:         7f2e8a1c-9b4d-4e3f-8c1a-6d5e7f8a9b0c
    Description:      Bootstrap Token (Global Management)
    Local:            false
    Create Time:      2026-04-16 10:20:15.678 +0000 UTC
    Policies:
       00000000-0000-0000-0000-000000000001 - global-management

    Save the SecretID immediately — it grants full admin rights and cannot be regenerated. Store it in your secrets manager alongside the gossip key.

    Export it into your shell for the rest of the session:

    bash
    export CONSUL_HTTP_TOKEN="7f2e8a1c-9b4d-4e3f-8c1a-6d5e7f8a9b0c"

    Create an agent policy so each node's agent can register itself and its services:

    bash
    cat > /tmp/agent-policy.hcl <<'EOF'
    node_prefix "" {
      policy = "write"
    }
    service_prefix "" {
      policy = "read"
    }
    EOF

    consul acl policy create \ -name "agent-policy" \ -description "Allow agents to register themselves" \ -rules @/tmp/agent-policy.hcl

    Create an agent token:

    bash
    consul acl token create \
      -description "Agent token for consul-1" \
      -policy-name "agent-policy"

    Copy the SecretID and configure it on each agent by adding the following to /etc/consul.d/consul.hcl:

    hcl
    acl {
      enabled                  = true
      default_policy           = "deny"
      enable_token_persistence = true

    tokens { agent = "PASTE_AGENT_TOKEN_HERE" } }

    Reload:

    bash
    sudo systemctl reload consul

    Repeat for consul-2 and consul-3 with their own agent tokens. Now nodes can register themselves under ACL enforcement.

    Step 8: Enable TLS for RPC and HTTPS

    Gossip encryption covers ports 8301/8302. RPC (8300) and the HTTP API (8500) are separate channels. Enable TLS end to end.

    Consul can generate its own CA:

    bash
    cd /etc/consul.d
    sudo -u consul consul tls ca create

    This produces consul-agent-ca.pem and consul-agent-ca-key.pem. Create a server certificate:

    bash
    sudo -u consul consul tls cert create -server -dc dc1

    Repeat the cert-create command on each server (it produces certs named dc1-server-consul-0.pem, -1, -2 — distribute accordingly). Also distribute consul-agent-ca.pem (public) to every node.

    Add the tls block to /etc/consul.d/consul.hcl on each server:

    hcl
    tls {
      defaults {
        ca_file   = "/etc/consul.d/consul-agent-ca.pem"
        cert_file = "/etc/consul.d/dc1-server-consul-0.pem"
        key_file  = "/etc/consul.d/dc1-server-consul-0-key.pem"

    verify_incoming = true verify_outgoing = true }

    internal_rpc { verify_server_hostname = true } }

    ports { http = -1 https = 8501 grpc_tls = 8503 }

    auto_encrypt { allow_tls = true }

    Setting http = -1 disables the plaintext HTTP port entirely — the UI and API are now only reachable over HTTPS on 8501. Reload:

    bash
    sudo systemctl restart consul

    Update your shell:

    bash
    export CONSUL_HTTP_ADDR="https://127.0.0.1:8501"
    export CONSUL_CACERT="/etc/consul.d/consul-agent-ca.pem"

    Verify:

    bash
    consul members

    If members still return, RPC-over-TLS and HTTPS are both working.

    Step 9: Register a Service and Add Health Checks

    Services can be registered two ways: via a config file picked up at agent startup, or via the HTTP API at runtime.

    Register via config file

    Assume you are running an HTTP API at http://127.0.0.1:9000/health. Create /etc/consul.d/web-service.hcl:

    hcl
    service {
      name = "web"
      id   = "web-1"
      port = 9000
      tags = ["api", "v1"]

    check { id = "web-health" name = "HTTP on port 9000" http = "http://127.0.0.1:9000/health" method = "GET" interval = "10s" timeout = "2s" } }

    Reload the agent:

    bash
    sudo systemctl reload consul

    Query the service:

    bash
    consul catalog services

    Expected output:

    text
    consul
    web

    Check health:

    bash
    consul health service -service web

    Or via HTTP:

    bash
    curl --cacert /etc/consul.d/consul-agent-ca.pem \
      -H "X-Consul-Token: $CONSUL_HTTP_TOKEN" \
      https://127.0.0.1:8501/v1/health/service/web

    Register via the HTTP API

    bash
    curl -X PUT --cacert /etc/consul.d/consul-agent-ca.pem \
      -H "X-Consul-Token: $CONSUL_HTTP_TOKEN" \
      -d '{
        "Name": "billing",
        "Port": 8080,
        "Check": {
          "HTTP": "http://127.0.0.1:8080/health",
          "Interval": "10s"
        }
      }' \
      https://127.0.0.1:8501/v1/agent/service/register

    Consul supports HTTP, TCP, gRPC, script, TTL, Docker, and alias check types. Failing checks remove the service from discovery results within one interval.

    Step 10: Use the KV Store

    Consul's KV store is a strongly consistent hierarchical key-value database — perfect for feature flags, dynamic config, and distributed locks.

    Write a key:

    bash
    consul kv put config/web/log_level "debug"

    Read it:

    bash
    consul kv get config/web/log_level

    Expected output:

    text
    debug

    List everything under a prefix:

    bash
    consul kv get -recurse config/

    Watch a key for changes (blocks until something changes):

    bash
    consul kv get -monitor config/web/log_level

    This is how applications implement live configuration reloads — they run a blocking query against Consul and rebuild their config the moment the value changes. Tools like consul-template extend this to render full config files from KV data and HUP the owning process.

    Distributed locking

    Use sessions to coordinate leader election between application instances:

    bash
    # Create a session with a 15s TTL
    SESSION=$(consul kv put -session - lock/my-app "locked" <<< '{"TTL":"15s"}')

    Only one instance can hold the lock at a time

    consul kv put -acquire -session=$SESSION lock/my-app "locked"

    Step 11: Enable Consul Connect Service Mesh

    Connect turns Consul into a full service mesh. Each service gets a sidecar proxy (Envoy by default) that terminates mTLS, and you control which services may talk to each other with intentions.

    Install Envoy

    Connect proxies are typically Envoy. On the nodes running application services:

    bash
    sudo apt install -y getenvoy-envoy

    Verify:

    bash
    envoy --version

    Register a service with a sidecar proxy

    Extend the service definition from Step 9 with a connect stanza:

    hcl
    service {
      name = "web"
      port = 9000

    connect { sidecar_service { proxy { upstreams = [ { destination_name = "billing" local_bind_port = 5000 } ] } } }

    check { http = "http://127.0.0.1:9000/health" interval = "10s" } }

    Reload the agent:

    bash
    sudo systemctl reload consul

    Start the sidecar proxy:

    bash
    consul connect envoy -sidecar-for web &

    Now the web service can reach the billing service by connecting to 127.0.0.1:5000. The sidecar establishes mTLS to billing's sidecar transparently — no application code changes required.

    Authorise traffic with intentions

    By default, Connect denies all service-to-service traffic. Allow web to talk to billing:

    bash
    consul intention create -allow web billing

    Deny public-api from reaching billing:

    bash
    consul intention create -deny public-api billing

    List intentions:

    bash
    consul intention list

    This gives you zero-trust east-west networking with centrally managed policy.

    Step 12: Resolve Services via DNS

    Consul exposes a DNS interface on port 8600 that answers queries in the format <service>.service.<datacenter>.consul:

    bash
    dig @127.0.0.1 -p 8600 web.service.dc1.consul

    Expected output:

    text
    ;; ANSWER SECTION:
    web.service.dc1.consul. 0 IN A 10.0.0.11

    SRV records include port information:

    bash
    dig @127.0.0.1 -p 8600 web.service.dc1.consul SRV

    Forward .consul queries system-wide

    Configure systemd-resolved to forward .consul queries to Consul:

    bash
    sudo mkdir -p /etc/systemd/resolved.conf.d
    sudo tee /etc/systemd/resolved.conf.d/consul.conf > /dev/null <<EOF
    [Resolve]
    DNS=127.0.0.1:8600
    Domains=~consul
    EOF

    sudo systemctl restart systemd-resolved

    Now any process on the node can resolve web.service.consul naturally — no port-8600 awareness required.

    Step 13: Access the Web UI

    With TLS enabled, the UI lives at https://<node>:8501/ui/. Because local exposure is safer than opening 8501 to the internet, tunnel it over SSH:

    bash
    ssh -L 8501:127.0.0.1:8501 [email protected]

    Open https://localhost:8501/ui/ in your browser. Accept the self-signed cert, then paste your bootstrap token when prompted.

    The UI shows:

    • Services — every registered service with pass/warning/critical counts
    • Nodes — every agent in the cluster with health
    • Key/Value — browse and edit KV entries
    • Intentions — the Connect policy graph
    • ACL — manage tokens, policies, and roles
    For internet-facing UI access, put Consul behind Nginx with client certificates or basic auth on top of HTTPS.

    Single-Server Dev Mode

    For development, skip the 3-node setup and run:

    bash
    sudo -u consul consul agent -dev -ui -client=0.0.0.0 \
      -data-dir=/tmp/consul

    Dev mode enables:

    • server = true with bootstrap_expect = 1
    • In-memory state (data lost on restart)
    • ACLs disabled
    • TLS disabled
    Perfect for trying features end to end, never safe for production.

    Alternatively, reuse this guide but set:

    hcl
    bootstrap_expect = 1
    retry_join       = []

    That gives you a persistent single-server cluster with TLS and ACLs still in force.

    Troubleshooting

    ProblemCauseSolution
    No cluster leaderRaft hasn't reached quorumCheck consul members — if servers are missing, verify port 8300 connectivity and matching gossip keys
    rpc error: rpc error making call: EOFTLS misconfiguredConfirm ca_file, cert_file, key_file paths exist, owned by consul, mode 640
    ACL not foundMissing or wrong tokenexport CONSUL_HTTP_TOKEN=.... Verify with consul acl token read -self
    encrypt has invalid key: must be exactly 32 bytesGossip key truncated or mismatchedRegenerate with consul keygen, paste identical value everywhere
    Service shows critical but is upHealth check target wrongRun the check command manually — e.g. curl http://127.0.0.1:9000/health — and match paths exactly
    dns: server failureLocal resolver not forwardingVerify systemd-resolved config and restart it
    High memory use on serversLarge KV dataset or many servicesTune raft_snapshot_threshold and performance.raft_multiplier in config
    failed to sync remote state: No known Consul serversClient cannot reach serversCheck retry_join and firewall rules on 8300-8302

    Logs

    bash
    sudo journalctl -u consul -n 200 --no-pager

    Enable log_level = "DEBUG" temporarily when debugging Raft or gossip issues — expect 10x the log volume.

    Raft state

    bash
    consul operator raft list-peers

    Confirms who the leader is and which nodes are voters.

    FAQ

    How many Consul servers do I need?

    A production cluster should run 3 or 5 Consul servers to tolerate 1 or 2 node failures respectively, since Raft requires a majority quorum. Three servers tolerate 1 failure; five tolerate 2; seven tolerate 3 but add latency because every write must reach a majority. Never run 2 servers — a single failure leaves you without a leader. For dev and testing a single server with bootstrap_expect = 1 is fine, but any reboot or crash is downtime.

    What ports does Consul use?

    TCP 8300 for server RPC, TCP/UDP 8301 for LAN gossip (Serf), TCP/UDP 8302 for WAN gossip between datacentres, TCP 8500 for the HTTP API and UI, TCP 8501 for HTTPS (when TLS is enabled), TCP/UDP 8600 for the DNS interface, TCP 8502/8503 for gRPC (used by Connect sidecars), and TCP 21000-21255 by default for sidecar proxies listening on each app node. Keep all of these on a private network — none should be exposed to the public internet.

    What is Consul Connect?

    Consul Connect is Consul's built-in service mesh. It issues short-lived mTLS certificates to every registered service and routes service-to-service traffic through sidecar proxies (Envoy or Consul's built-in proxy) that enforce authorisation rules called intentions. It gives you zero-trust networking between microservices with no application code changes — your app just opens a plain TCP connection to localhost:, and the sidecar handles certificate issuance, rotation, mTLS termination, and policy enforcement. Connect is a direct alternative to Istio and Linkerd, and unlike those it runs without Kubernetes.

    How does Consul compare to etcd and ZooKeeper?

    All three provide strongly consistent distributed KV storage via Raft or Paxos-style consensus. Consul adds first-class service discovery, health checking, a DNS interface, multi-DC federation, and a built-in service mesh. etcd is simpler, smaller, and is the storage backend behind Kubernetes — excellent when you need just a fast embedded KV and nothing else. ZooKeeper is older, tested in the Hadoop/Kafka ecosystem, but its API is lower-level and service discovery is bolted on via third-party libraries. Pick Consul when you want discovery plus mesh out of the box; pick etcd when your app only needs KV; pick ZooKeeper when you already run Hadoop or Kafka.

    Do I need TLS if I already have gossip encryption?

    Yes. Gossip encryption only protects Serf traffic on ports 8301 and 8302. RPC traffic between agents (port 8300), HTTP API calls (ports 8500/8501), and gRPC for sidecars (8502/8503) are all separate channels. For production you must enable TLS with verify_incoming = true, verify_outgoing = true, and verify_server_hostname = true on the internal RPC channel. Without TLS, an attacker on the same network can read ACL tokens, KV data, and Connect certificates in plaintext.

    Can Consul share nodes with Vault and Nomad?

    Yes, and HashiCorp explicitly recommends it for small-to-medium clusters. Run Consul, Vault, and Nomad servers on the same three VPS instances. Vault uses Consul as its storage backend. Nomad uses Consul for service discovery. On three CloudCore Professional nodes (12 GB RAM each) all three services together consume 1-2 GB RAM total, leaving plenty of headroom for application workloads.

    How do I upgrade Consul safely?

    With the apt repo, upgrade one node at a time:

  • sudo apt update && sudo apt install --only-upgrade consul
  • sudo systemctl restart consul
  • Wait for consul operator raft list-peers to show the node rejoining
  • Repeat on the next server
  • Upgrade followers first, leader last. For major version jumps, read HashiCorp's upgrade notes — some versions require intermediate hops.

    Next Steps

    Consul is the nervous system of your infrastructure. Here's what to layer on top:

    • Install Vault — HashiCorp Vault uses Consul as its storage backend and integrates natively with Consul Connect for PKI-based certificate issuance. Running both on the same three nodes is the canonical HashiCorp stack pattern.
    • Install Nomad — Nomad is HashiCorp's scheduler. It automatically registers jobs as Consul services, emits health checks, and wires up Connect sidecars. A Consul + Nomad deployment is a lighter alternative to Kubernetes.
    • Install etcd — If you just need a distributed KV store without the rest of Consul, etcd is smaller and simpler. Useful for embedding in custom control planes.
    • Set up consul-template — Render config files from KV values and SIGHUP the owning process on change. The classic pattern for zero-downtime config reloads on apps that don't natively integrate with Consul.
    • Explore the official Consul docs — Deep dives on Raft tuning, WAN federation, admin partitions, and Envoy extensions.
    • Export metrics to Prometheus — Consul exposes /v1/agent/metrics?format=prometheus when telemetry.prometheus_retention_time is set. Scrape it to watch Raft apply latency, gossip churn, and KV operation rates.

    Prefer a One-Click Consul Cluster?
    >
    Our CloudCore Professional plan is the ideal foundation for a 3-node Consul cluster with Vault and Nomad co-located. EUR 19.99/month per node — deploy three and you have a full HashiCorp control plane for under EUR 60/month.
    >
    - 6 vCPU cores, 12 GB RAM, 100 GB NVMe per node
    - Private networking included — perfect for gossip and Raft
    - Ubuntu 24.04 LTS pre-installed
    - Unmetered bandwidth
    >
    Deploy CloudCore Professional and start Step 1 in five minutes.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket