Set Up Consul Service Discovery on VPS

Set Up Consul Service Discovery on VPS

July 2026 · 8 min read

Consul is HashiCorp's service discovery tool that enables microservices on a VPS to find each other automatically without hardcoded IP addresses in configuration files. Consul registers services, performs health checks, and maintains a distributed key-value store, allowing microservice architectures to adapt dynamically as servers start, stop, or require configuration changes without restarting the entire web application.

Install Consul

The easiest way is to download the binary from HashiCorp:

# Download latest Consul release
cd /tmp
wget https://releases.hashicorp.com/consul/1.18.0/consul_1.18.0_linux_amd64.zip

# Extract and move to /usr/local/bin
unzip consul_1.18.0_linux_amd64.zip
sudo mv consul /usr/local/bin/
chmod +x /usr/local/bin/consul

# Verify installation
consul version

Or use apt package manager if available:

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt update
sudo apt install consul -y

Run Consul Agent as First Server (Development)

For testing on a single VPS, run the agent in server mode with bootstrap-expect=1:

# Create directory for Consul data
mkdir -p /opt/consul

# Start Consul server
sudo consul agent -server \
  -ui \
  -bootstrap-expect=1 \
  -data-dir=/opt/consul \
  -client=0.0.0.0 \
  -bind=127.0.0.1 \
  -node=consul-server-1

When Consul starts, you should see output similar to:

==> Starting Consul agent...
==> Consul agent running!
         Node name: consul-server-1
        Datacenter: dc1
            Server: true (bootstrap: true)
       Client Addr: 127.0.0.1 (HTTP: 8500, DNS: 8600)
      Cluster Addr: 127.0.0.1 (LAN: 8301 TCP/UDP, WAN: 8302 TCP/UDP)
Tip: This development setup is suitable for single VPS or testing environments. For production multi-server clusters, set bootstrap-expect to match the number of servers (e.g., 3 servers = bootstrap-expect=3) and use HCL configuration files instead of command-line flags.

Register Services with Configuration File

Create a JSON file to tell Consul which services are running:

# Create /etc/consul.d/services.json
{
  "services": [
    {
      "id": "web-1",
      "name": "web",
      "port": 8080,
      "address": "127.0.0.1",
      "check": {
        "http": "http://127.0.0.1:8080/health",
        "interval": "10s"
      }
    },
    {
      "id": "api-1",
      "name": "api",
      "port": 3000,
      "address": "127.0.0.1",
      "check": {
        "http": "http://127.0.0.1:3000/status",
        "interval": "10s"
      }
    }
  ]
}

Tell Consul to reload this configuration:

sudo curl -X PUT --data-binary @/etc/consul.d/services.json \
  http://127.0.0.1:8500/v1/agent/reload

Use Consul KV Store for Configuration

Consul includes a built-in key-value store for centralized configuration:

# Store configuration values
consul kv put app/config/db_host "postgres.internal"
consul kv put app/config/db_port "5432"
consul kv put app/config/redis_url "redis://cache.internal:6379"

# Retrieve values
consul kv get app/config/db_host
consul kv get -recurse app/config/

Applications can fetch values from the Consul HTTP API:

curl http://127.0.0.1:8500/v1/kv/app/config/db_host?raw

Verify That Consul Is Working Correctly

# View all Consul members (nodes connected to the cluster)
consul members

# List all registered services
consul catalog services

# View node information
consul info

# Check service health status via HTTP API
curl http://127.0.0.1:8500/v1/health/state/passing

# View all health checks
curl http://127.0.0.1:8500/v1/agent/checks
Tip: Open the Consul UI in your web browser at http://127.0.0.1:8500 to see a convenient overview of services, nodes, and key-value data.

Common Issues & Troubleshooting

Error: "Address already in use" (Port 8500 conflict)

Port 8500 (HTTP API) or 8301 (LAN gossip) is occupied by another process. Find which process is using it:

sudo lsof -i :8500
sudo lsof -i :8301

# If conflict exists, either kill the process or change Consul's port
sudo consul agent -server -http-addr 127.0.0.1:8501 -client=0.0.0.0

Error: "agent: failed to sync remote state: permission denied"

Consul lacks permission to read/write the data or config directory. Check file permissions:

sudo chown -R consul:consul /opt/consul
sudo chown -R consul:consul /etc/consul.d
sudo chmod 755 /opt/consul /etc/consul.d

Health check is failing (health status red)

Consul reports that a service is unhealthy. Verify the HTTP health endpoint responds:

# Test the health endpoint manually
curl http://127.0.0.1:8080/health -v

# View detailed health check status in Consul
curl http://127.0.0.1:8500/v1/agent/checks | jq '.'

# Check system logs for health check errors
grep "health check" /var/log/syslog

Service doesn't appear in catalog despite registration

Verify the service definition JSON is valid and reload Consul:

# Validate JSON syntax
cat /etc/consul.d/services.json | jq .

# Reload the agent
consul reload

# Check if service is in the catalog
consul catalog services -service=web

Agent cannot join the cluster (failed to join)

Verify firewall rules are open and the target address is correct:

# Attempt to join the cluster
consul join 192.168.1.100:8301

# If join fails, open firewall ports
sudo ufw allow 8300/tcp
sudo ufw allow 8301/tcp
sudo ufw allow 8301/udp
sudo ufw allow 8302/tcp
sudo ufw allow 8302/udp

Frequently Asked Questions

How does Consul differ from Eureka or etcd?

Consul is an all-in-one tool combining service discovery, health checking, KV storage, and multi-datacenter support. Eureka is service discovery only (used in Spring Cloud), while etcd is a KV store that requires additional tools for service discovery. Consul was designed to work standalone without dependency on multiple tools.

Do I need a load balancer or OS-level health checks separately?

Consul health checks only report service status—they don't provide automated failover. Health checks alone are insufficient for production. Pair Consul with systemd units for automatic restarts or use orchestration platforms like Kubernetes or Docker Swarm for true high availability and automatic service replacement.

Does Consul support HA mode for production?

Yes. For production, set up a Consul cluster with 3 or 5 servers (odd number) using bootstrap-expect matching the count. All servers must communicate via gossip protocol on port 8301 and maintain quorum for Raft consensus. With 3 servers, losing 1 still allows the cluster to function with 2 remaining servers reaching quorum.