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?
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.
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 = 1is 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-3or 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:
sudo apt update && sudo apt upgrade -yInstall prerequisites:
sudo apt install -y curl gnupg lsb-release software-properties-common unzip jqSet a unique hostname on each node:
# On consul-1
sudo hostnamectl set-hostname consul-1On consul-2
sudo hostnamectl set-hostname consul-2On consul-3
sudo hostnamectl set-hostname consul-3Add each node to /etc/hosts on all three machines so they can resolve each other by name:
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
EOFOpen the required firewall ports between the Consul nodes:
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:
wget -O- https://apt.releases.hashicorp.com/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpgAdd the apt repository:
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.listUpdate the package index:
sudo apt updateExpected output:
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... DoneStep 3: Install the Consul Package
Install Consul on all three nodes:
sudo apt install -y consulVerify the installed version:
consul versionExpected output:
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
consulbinary at/usr/bin/consul - A dedicated
consulsystem user and group - The data directory
/opt/consul - The config directory
/etc/consul.dwith a stubconsul.hcl - A systemd unit at
/usr/lib/systemd/system/consul.service
/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:
consul keygenExpected output:
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
sudo tee /etc/consul.d/consul.hcl > /dev/null <<'EOF' datacenter = "dc1" data_dir = "/opt/consul" node_name = "consul-1" server = true bootstrap_expect = 3bind_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 severaldatacenters.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 setserver = false.bootstrap_expect = 3— Wait for 3 servers to be available before electing a leader. For a single-server dev cluster set this to1. Never set it to2— 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.0is fine here because UFW already restricts access.retry_join— List of peers to try contacting on startup. Unlikejoin, 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 athttp://<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:
sudo chown -R consul:consul /etc/consul.d /opt/consul
sudo chmod 640 /etc/consul.d/consul.hclCreate and own the log directory:
sudo mkdir -p /var/log/consul
sudo chown consul:consul /var/log/consulValidate the config before starting:
sudo -u consul consul validate /etc/consul.d/Expected output:
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):
sudo systemctl enable --now consulCheck status:
sudo systemctl status consulExpected output:
● 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:
sudo journalctl -u consul -fLook for a line like:
[INFO] agent.server.raft: entering leader state: leader="Node at 10.0.0.11:8300 [Leader]"
[INFO] agent: Synced node infoConfirm cluster membership from any node:
consul membersExpected output:
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):
consul acl bootstrapExpected output:
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-managementSave 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:
export CONSUL_HTTP_TOKEN="7f2e8a1c-9b4d-4e3f-8c1a-6d5e7f8a9b0c"Create an agent policy so each node's agent can register itself and its services:
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:
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:
acl { enabled = true default_policy = "deny" enable_token_persistence = true
tokens { agent = "PASTE_AGENT_TOKEN_HERE" } }
Reload:
sudo systemctl reload consulRepeat 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:
cd /etc/consul.d
sudo -u consul consul tls ca createThis produces consul-agent-ca.pem and consul-agent-ca-key.pem. Create a server certificate:
sudo -u consul consul tls cert create -server -dc dc1Repeat 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:
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:
sudo systemctl restart consulUpdate your shell:
export CONSUL_HTTP_ADDR="https://127.0.0.1:8501"
export CONSUL_CACERT="/etc/consul.d/consul-agent-ca.pem"Verify:
consul membersIf 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:
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:
sudo systemctl reload consulQuery the service:
consul catalog servicesExpected output:
consul
webCheck health:
consul health service -service webOr via HTTP:
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/webRegister via the HTTP API
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/registerConsul 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:
consul kv put config/web/log_level "debug"Read it:
consul kv get config/web/log_levelExpected output:
debugList everything under a prefix:
consul kv get -recurse config/Watch a key for changes (blocks until something changes):
consul kv get -monitor config/web/log_levelThis 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:
# 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:
sudo apt install -y getenvoy-envoyVerify:
envoy --versionRegister a service with a sidecar proxy
Extend the service definition from Step 9 with a connect stanza:
service { name = "web" port = 9000connect { 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:
sudo systemctl reload consulStart the sidecar proxy:
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:
consul intention create -allow web billingDeny public-api from reaching billing:
consul intention create -deny public-api billingList intentions:
consul intention listThis 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:
dig @127.0.0.1 -p 8600 web.service.dc1.consulExpected output:
;; ANSWER SECTION:
web.service.dc1.consul. 0 IN A 10.0.0.11SRV records include port information:
dig @127.0.0.1 -p 8600 web.service.dc1.consul SRVForward .consul queries system-wide
Configure systemd-resolved to forward .consul queries to Consul:
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:
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
Single-Server Dev Mode
For development, skip the 3-node setup and run:
sudo -u consul consul agent -dev -ui -client=0.0.0.0 \
-data-dir=/tmp/consulDev mode enables:
server = truewithbootstrap_expect = 1- In-memory state (data lost on restart)
- ACLs disabled
- TLS disabled
Alternatively, reuse this guide but set:
bootstrap_expect = 1
retry_join = []That gives you a persistent single-server cluster with TLS and ACLs still in force.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
No cluster leader | Raft hasn't reached quorum | Check consul members — if servers are missing, verify port 8300 connectivity and matching gossip keys |
rpc error: rpc error making call: EOF | TLS misconfigured | Confirm ca_file, cert_file, key_file paths exist, owned by consul, mode 640 |
ACL not found | Missing or wrong token | export CONSUL_HTTP_TOKEN=.... Verify with consul acl token read -self |
encrypt has invalid key: must be exactly 32 bytes | Gossip key truncated or mismatched | Regenerate with consul keygen, paste identical value everywhere |
Service shows critical but is up | Health check target wrong | Run the check command manually — e.g. curl http://127.0.0.1:9000/health — and match paths exactly |
dns: server failure | Local resolver not forwarding | Verify systemd-resolved config and restart it |
| High memory use on servers | Large KV dataset or many services | Tune raft_snapshot_threshold and performance.raft_multiplier in config |
failed to sync remote state: No known Consul servers | Client cannot reach servers | Check retry_join and firewall rules on 8300-8302 |
Logs
sudo journalctl -u consul -n 200 --no-pagerEnable log_level = "DEBUG" temporarily when debugging Raft or gossip issues — expect 10x the log volume.
Raft state
consul operator raft list-peersConfirms 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 consulsudo systemctl restart consulconsul operator raft list-peers to show the node rejoiningUpgrade 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=prometheuswhentelemetry.prometheus_retention_timeis 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.