HashiQube - DevOps Lab
Youtube Channel Medium Posts Riaan Nolan Linkedin Riaan Nolan Hashicorp Ambassador

.

Nomad

Nomad Logo

In this HashiQube DevOps lab you will get hands on experience with HashiCorp Nomad.

Nomad is a highly available, distributed, data-center aware cluster and application scheduler designed to support the modern datacenter with support for

Increasingly, teams want to move away from the traditional tight coupling of application and operating system. So they need an abstraction layer to help developers and operators work together, and save money with better hardware utilization. Introducing HashiCorp Nomad.

Latest News

Introduction

Introduction to HashiCorp Nomad

Provision

Open in GitHub Codespaces

bash docker/docker.sh
bash consul/consul.sh
bash nomad/nomad.sh
vagrant up --provision-with basetools,docker,docsify,consul,nomad
docker compose exec hashiqube /bin/bash
bash hashiqube/basetools.sh
bash docker/docker.sh
bash consul/consul.sh
bash nomad/nomad.sh

Nomad

Nomad Provisioner

nomad.sh

#!/bin/bash

VERSION=latest

arch=$(lscpu | grep "Architecture" | awk '{print $NF}')
if [[ $arch == x86_64* ]]; then
  ARCH="amd64"
elif  [[ $arch == aarch64 ]]; then
  ARCH="arm64"
fi
echo -e '\e[38;5;198m'"CPU is $ARCH"

# https://github.com/hashicorp/nomad/issues/19343 nomad needs dmidecode
sudo DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install -qq dmidecode curl unzip jq < /dev/null > /dev/null

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Cleanup any Nomad if found"
echo -e '\e[38;5;198m'"++++ "
sudo systemctl stop nomad
sudo rm -rf /etc/nomad
sudo rm -rf /var/lib/nomad
sudo rm -rf /opt/nomad
sudo rm -rf /tmp/nomad.zip
sudo rm -rf /opt/cni
sudo rm -rf /tmp/cni-plugins.tgz
yes | sudo docker system prune -a
yes | sudo docker system prune --volumes

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Consul is running (Dependency)"
echo -e '\e[38;5;198m'"++++ "
if pgrep -x "consul" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ Consul is running"
else
  echo -e '\e[38;5;198m'"++++ Ensure Consul is running.."
  sudo bash /vagrant/consul/consul.sh
fi

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Ensure Docker Daemon is running (Dependency)"
echo -e '\e[38;5;198m'"++++ "
if pgrep -x "dockerd" >/dev/null
then
  echo -e '\e[38;5;198m'"++++ Docker is running"
else
  echo -e '\e[38;5;198m'"++++ Ensure Docker is running.."
  sudo bash /vagrant/docker/docker.sh
fi

if [ -f /vagrant/nomad/license.hclic ]; then
  # https://developer.hashicorp.com/nomad/tutorials/enterprise/hashicorp-enterprise-license
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Found license.hclic Installing Enterprise Edition version: $VERSION"
  echo -e '\e[38;5;198m'"++++ "
  export NOMAD_LICENSE_PATH=/vagrant/nomad/license.hclic
  export NOMAD_LICENSE=$(cat /vagrant/nomad/license.hclic)
  if [[ $VERSION == "latest" ]]; then
    LATEST_URL=$(curl -sL https://releases.hashicorp.com/nomad/index.json | jq -r '.versions[].builds[].url' | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | egrep 'ent' | egrep "linux.*$ARCH" | sort -V | tail -n 1)
  else
    LATEST_URL=$(curl -sL https://releases.hashicorp.com/nomad/index.json | jq -r '.versions[].builds[].url' | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | egrep 'ent' | egrep "linux.*$ARCH" | sort -V | grep $VERSION | tail -1)
  fi
else
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Installing Community Edition version: $VERSION"
  echo -e '\e[38;5;198m'"++++ "
  if [[ $VERSION == "latest" ]]; then
    LATEST_URL=$(curl -sL https://releases.hashicorp.com/nomad/index.json | jq -r '.versions[].builds[].url' | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | egrep -v 'rc|ent|beta' | egrep "linux.*$ARCH" | sort -V | tail -n 1)
  else
    LATEST_URL=$(curl -sL https://releases.hashicorp.com/nomad/index.json | jq -r '.versions[].builds[].url' | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | egrep -v 'rc|ent|beta' | egrep "linux.*$ARCH" | sort -V | grep $VERSION | tail -1)
  fi
fi
wget -q $LATEST_URL -O /tmp/nomad.zip

mkdir -p /usr/local/bin
(cd /usr/local/bin && unzip -o /tmp/nomad.zip)
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Installed `/usr/local/bin/nomad --version`"
echo -e '\e[38;5;198m'"++++ "

# create /var/log/nomad.log
sudo touch /var/log/nomad.log

# create Nomad data directories
sudo mkdir -p /etc/nomad

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create Nomad Systemd service file"
echo -e '\e[38;5;198m'"++++ "
# create a Nomad service file at /etc/systemd/system/nomad.service
cat <<EOF | sudo tee /etc/systemd/system/nomad.service
[Unit]
Description=Nomad
Documentation=https://nomadproject.io/docs/
Wants=network-online.target
After=network-online.target

# When using Nomad with Consul it is not necessary to start Consul first. These
# lines start Consul before Nomad as an optimization to avoid Nomad logging
# that Consul is unavailable at startup.
#Wants=consul.service
#After=consul.service

[Service]
# EnvironmentFile=/etc/nomad.d/nomad.env
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/nomad agent -config=/etc/nomad/server.conf -dev-connect
KillMode=process
KillSignal=SIGINT
LimitNOFILE=65536
LimitNPROC=infinity
Restart=on-failure
RestartSec=2
LogsDirectory=nomad
StandardOutput=append:/var/log/nomad.log
StandardError=append:/var/log/nomad.log
StartLimitBurst=3

## Configure unit start rate limiting. Units which are started more than
## *burst* times within an *interval* time span are not permitted to start any
## more. Use StartLimitIntervalSec or StartLimitInterval (depending on
## systemd version) to configure the checking interval and StartLimitBurst
## to configure how many starts per interval are allowed. The values in the
## commented lines are defaults.

TasksMax=infinity
OOMScoreAdjust=-1000

[Install]
WantedBy=multi-user.target
EOF

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Create Nomad config file /etc/nomad/server.conf"
echo -e '\e[38;5;198m'"++++ "
cat <<EOF | sudo tee /etc/nomad/server.conf
data_dir  = "/var/lib/nomad"

bind_addr = "0.0.0.0" # the default

datacenter = "dc1"

advertise {
  # Defaults to the first private IP address.
  http = "{{ GetInterfaceIP \"eth0\" }}"
  rpc  = "{{ GetInterfaceIP \"eth0\" }}"
  serf = "{{ GetInterfaceIP \"eth0\" }}:5648" # non-default ports may be specified
}

server {
  enabled          = true
  bootstrap_expect = 1
}

autopilot {
  cleanup_dead_servers      = true
  last_contact_threshold    = "400ms"
  max_trailing_logs         = 250
  server_stabilization_time = "30s"
  enable_redundancy_zones   = false
  disable_upgrade_migration = false
  enable_custom_upgrades    = false
}

client {
  enabled       = true
  # https://github.com/hashicorp/nomad/issues/1282
  network_speed = 100
  # https://developer.hashicorp.com/nomad/docs/configuration/client#cpu_total_compute
  # BUG: CPU fingerprint with Docker Desktop on Apple Silicon never really worked because the CPU speed is not made available anywhere, so its impossible for Nomad to detect it
  # If you run previous versions of Nomad you will notice that the fingerprinted capacity is always 1000MHz. This is a value we used to hardcode as a fallback but we dont anymore on 1.7.x (https://github.com/hashicorp/nomad/blob/release/1.6.x/client/fingerprint/cpu.go#L23) because its just wrong.
  # The only option for now is to pass their own hardcoded value using client.cpu_total_compute (https://developer.hashicorp.com/nomad/docs/configuration/client#cpu_total_compute)
  cpu_total_compute = 8000
  servers = ["{{ GetInterfaceIP \"eth0\" }}:4647"]
  # network_interface = "enp0s8"
  # https://www.nomadproject.io/docs/drivers/docker.html#volumes
  # https://github.com/hashicorp/nomad/issues/5562
  options = {
    "docker.volumes.enabled" = true
    "docker.auth.config"     = "/etc/docker/auth.json"
  }
  host_volume "waypoint" {
    path      = "/opt/nomad/data/volume/waypoint"
    read_only = false
  }
}

plugin "docker" {
  config {
    endpoint = "unix:///var/run/docker.sock"

    volumes {
      enabled      = true
      selinuxlabel = "z"
    }

    allow_privileged = true
    allow_caps       = ["chown", "net_raw"]
  }
}

plugin "raw_exec" {
  config {
    enabled = true
  }
}

# https://developer.hashicorp.com/nomad/docs/configuration/telemetry
# https://developer.hashicorp.com/nomad/docs/configuration/telemetry#prometheus
# https://developer.hashicorp.com/nomad/docs/operations/monitoring-nomad
telemetry {
  collection_interval = "1s"
  disable_hostname = true
  prometheus_metrics = true
  publish_allocation_metrics = true
  publish_node_metrics = true
}

consul {
  address = "{{ GetInterfaceIP \"eth0\" }}:8500"
}
EOF
if [ -f /vagrant/nomad/license.hclic ]; then
  sed -i -e 's;bootstrap_expect = 1;bootstrap_expect = 1\n  license_path = "/vagrant/nomad/license.hclic";' /etc/nomad/server.conf
fi

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Creating Waypoint host volume /opt/nomad/data/volume/waypoint"
echo -e '\e[38;5;198m'"++++ "
sudo mkdir -p /opt/nomad/data/volume/waypoint
sudo chmod -R 777 /opt/nomad

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Check if CNI Plugins are installed"
echo -e '\e[38;5;198m'"++++ "
if [ -f /opt/cni/bin/bridge ]; then
  echo -e '\e[38;5;198m'"++++ CNI Plugins already installed"
else
  echo -e '\e[38;5;198m'"++++ CNI Plugins not found, installing.."
  wget -q https://github.com/containernetworking/plugins/releases/download/v1.4.1/cni-plugins-linux-$ARCH-v1.4.1.tgz -O /tmp/cni-plugins.tgz
  mkdir -p /opt/cni/bin
  tar -C /opt/cni/bin -xzf /tmp/cni-plugins.tgz
  echo 1 > /proc/sys/net/bridge/bridge-nf-call-arptables
  echo 1 > /proc/sys/net/bridge/bridge-nf-call-ip6tables
  echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
fi

# start and enable nomad service to start on system boot
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Start Nomad Service"
echo -e '\e[38;5;198m'"++++ "
sudo systemctl daemon-reload
sudo service nomad start
sh -c 'sudo tail -f /var/log/nomad.log | { sed "/node registration complete/ q" && kill $$ ;}'
sleep 2

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Get Nomad Members and Status"
echo -e '\e[38;5;198m'"++++ "
sleep 10
nomad server members
nomad node status

cd /vagrant/nomad/nomad/jobs;
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Start Nomad Fabio job"
echo -e '\e[38;5;198m'"++++ "
nomad plan --address=http://localhost:4646 fabio.nomad
nomad run --address=http://localhost:4646 fabio.nomad
# # curl -v -H 'Host: fabio.service.consul' http://${VAGRANT_IP}:9999/

echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Start Nomad Traefik job"
echo -e '\e[38;5;198m'"++++ "
nomad plan --address=http://localhost:4646 traefik.nomad
nomad run --address=http://localhost:4646 traefik.nomad
# nomad plan --address=http://localhost:4646 traefik-whoami.nomad
# nomad run --address=http://localhost:4646 traefik-whoami.nomad

if [ -f /vagrant/nomad/license.hclic ]; then
  echo -e '\e[38;5;198m'"++++ "
  echo -e '\e[38;5;198m'"++++ Nomad License Inspect"
  echo -e '\e[38;5;198m'"++++ "
  nomad license inspect /vagrant/nomad/license.hclic
fi
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Access Nomad"
echo -e '\e[38;5;198m'"++++ "
echo -e '\e[38;5;198m'"++++ Nomad http://localhost:4646"
echo -e '\e[38;5;198m'"++++ Nomad Documentation http://localhost:3333/#/nomad/README?id=nomad"
echo -e '\e[38;5;198m'"++++ Fabio Dashboard http://localhost:9998"
echo -e '\e[38;5;198m'"++++ Fabio Loadbalancer http://localhost:9998"
echo -e '\e[38;5;198m'"++++ Fabio Documentation http://localhost:3333/#/nomad/README?id=fabio-load-balancer-for-nomad"
echo -e '\e[38;5;198m'"++++ Treafik Dashboard http://localhost:38081"
echo -e '\e[38;5;198m'"++++ Traefik Loadbalancer: http://localhost:38080"
echo -e '\e[38;5;198m'"++++ Traefik Documentation: http://localhost:3333/#/nomad/README?id=traefik-load-balancer-for-nomad"

Monitoring Nomad

We use Prometheus and Grafana to Monitor Nomad

See: Monitoring Hashicorp Nomad

Traefik on Nomad

https://traefik.io/blog/traefik-proxy-fully-integrates-with-hashicorp-nomad/
https://doc.traefik.io/traefik/v2.8/providers/nomad/

Traefik Logo

We are thrilled to announce the full integration of the new Nomad built-in Service Discovery with Traefik Proxy. This is a first-of-its-kind ingress integration that simplifies ingress in HashiCorp Nomad. Utilizing Nomad directly with Traefik Proxy has never been so easy!

In early May, Hashicorp announced Nomad Version 1.3. Among other updates, it also includes a nice list of improvements on usability and developer experience. Before this release, when using service discovery with Nomad, Traefik Proxy users had to use Hashicorp Consul and Nomad side-by-side in order to benefit from Traefik Proxy’s famous automatic configuration. Now, Nomad has a simple and straightforward way to use service discovery built-in. This improves direct usability a lot! Not only in simple test environments but also on the edge.

http://localhost:8080/ and http://localhost:8181

Traefik Load Balancer

Traefik Load Balancer

Traefik Nomad Job

# https://traefik.io/blog/traefik-proxy-fully-integrates-with-hashicorp-nomad/

job "traefik" {
  datacenters = ["dc1"]
  type        = "system"

  group "traefik" {
    count = 1

    network {
      port  "http"{
         static = 38080
      }
      port  "admin"{
         static = 38081
      }
    }

    service {
      name = "traefik"
      provider = "consul"
      port = "admin"
      tags = ["urlprefix-traefik.service.consul/", "urlprefix-/"]
      check {
        type     = "http"
        path     = "/dashboard/"
        port     = "admin"
        interval = "10s"
        timeout  = "2s"
      }
    }

    task "server" {
      driver = "docker"
      config {
        image = "traefik:latest"
        ports = ["admin", "http"]
        args = [
          "--api.dashboard=true",
          "--api.insecure=true", ### For Test only, please do not use that in production
          "--entrypoints.web.address=0.0.0.0:${NOMAD_PORT_http}",
          "--entrypoints.traefik.address=0.0.0.0:${NOMAD_PORT_admin}",
          "--providers.nomad=true",
          "--providers.nomad.endpoint.address=http://${attr.unique.network.ip-address}:4646" ### IP to your nomad server
        ]
      }
    }
  }
}

vagrant up --provision-with basetools,docker,docsify,consul,nomad

The new native Service Discovery in Nomad really does work seamlessly. With this integration, delivering load balancing, dynamic routing configuration, and ingress traffic routing become easier than ever. Check out the Traefik Proxy 2.8 Release Candidate and the Nomad 1.3 release notes.

curl -H "Host: whoami.nomad.localhost" http://localhost:8080 -v

*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: whoami.nomad.localhost
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Length: 365
< Content-Type: text/plain; charset=utf-8
< Date: Thu, 16 Jun 2022 02:08:56 GMT
< 
Hostname: 86bb7e3d366a
IP: 127.0.0.1
IP: 172.18.0.5
RemoteAddr: 172.18.0.1:51192
GET / HTTP/1.1
Host: whoami.nomad.localhost
User-Agent: curl/7.79.1
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.17.0.1
X-Forwarded-Host: whoami.nomad.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 5d7dc64220c8
X-Real-Ip: 172.17.0.1

* Connection #0 to host localhost left intact

Traefik Whoami

# https://traefik.io/blog/traefik-proxy-fully-integrates-with-hashicorp-nomad/

job "traefik-whoami" {
  datacenters = ["dc1"]

  type = "service"

  group "traefik-whoami" {
    count = 1

    network {
       port "http" {
         to = 38080
       }
    }

    service {
      name = "traefik-whoami"
      port = "http"
      provider = "nomad"

      tags = [
        "traefik.enable=true",
        "traefik.http.routers.http.rule=Host(`whoami.nomad.localhost`)",
      ]
    }

    task "server" {
      env {
        WHOAMI_PORT_NUMBER = "${NOMAD_PORT_http}"
      }

      driver = "docker"

      config {
        image = "traefik/whoami"
        ports = ["http"]
      }
    }
  }
}

Fabio on Nomad

https://github.com/fabiolb/fabio
https://fabiolb.net

Fabio is an HTTP and TCP reverse proxy that configures itself with data from Consul.

Traditional load balancers and reverse proxies need to be configured with a config file. The configuration contains the hostnames and paths the proxy is forwarding to upstream services. This process can be automated with tools like consul-template that generate config files and trigger a reload.

Fabio works differently since it updates its routing table directly from the data stored in Consul as soon as there is a change and without restart or reloading.

When you register a service in Consul all you need to add is a tag that announces the paths the upstream service accepts, e.g. urlprefix-/user or urlprefix-/order and fabio will do the rest.

http://localhost:9999/ and http://localhost:9998

Fabio Load Balancer

vagrant up --provision-with basetools,docker,docsify,consul,nomad

Fabio runs as a Nomad job, see nomad/nomad/jobs/fabio.nomad

Some routes are added via Consul, see consul/consul.sh

Fabio Nomad Job

# https://learn.hashicorp.com/nomad/load-balancing/fabio
job "fabio" {
  datacenters = ["dc1"]
  type = "system"

  group "fabio" {

    network {
      port "lb" {
        static = 9999
      }
      port "ui" {
        static = 9998
      }
    }

    task "fabio" {
      driver = "docker"
      config {
        image = "fabiolb/fabio"
        network_mode = "host"
        # https://www.nomadproject.io/docs/drivers/docker.html#volumes
        # https://github.com/hashicorp/nomad/issues/5562
        mounts = [
          {
            type   = "bind"
            target = "/etc/fabio"
            source = "/vagrant/nomad/nomad/jobs"
          },
        ]
        #volumes = [
        #  # Use absolute paths to mount arbitrary paths on the host
        #  "/vagrant/nomad/nomad/jobs:/etc/fabio"
        #]
      }

      env {
        NOMAD_IP_elb = "0.0.0.0"
        NOMAD_IP_admin = "0.0.0.0"
        NOMAD_IP_tcp = "0.0.0.0"
        NOMAD_ADDR_ui = "0.0.0.0:9998"
        NOMAD_ADDR_lb = "0.0.0.0:9999"
      }

      resources {
        cpu    = 200
        memory = 128
      }

      service {
        port = "ui"
        name = "fabio"
        tags = ["urlprefix-fabio.service.consul/", "urlprefix-/", "urlprefix-/routes"]
        check {
           type     = "http"
           path     = "/health"
           port     = "ui"
           interval = "10s"
           timeout  = "2s"
         }
      }

    }
  }
}

Fabio Properties

# proxy.cs configures one or more certificate sources.
#
# Each certificate source is configured with a list of
# key/value options. Each source must have a unique
# name which can then be referred to in a listener
# configuration.
#
#   cs=<name>;type=<type>;opt=arg;opt[=arg];...
#
# All certificates need to be provided in PEM format.
#
# The following types of certificate sources are available:
#
# File
#
# The file certificate source supports one certificate which is loaded at
# startup and is cached until the service exits.
#
# The 'cert' option contains the path to the certificate file. The 'key'
# option contains the path to the private key file. If the certificate file
# contains both the certificate and the private key the 'key' option can be
# omitted. The 'clientca' option contains the path to one or more client
# authentication certificates.
#
#   cs=<name>;type=file;cert=p/a-cert.pem;key=p/a-key.pem;clientca=p/clientAuth.pem
#
# Path
#
# The path certificate source loads certificates from a directory in
# alphabetical order and refreshes them periodically.
#
# The 'cert' option provides the path to the TLS certificates and the
# 'clientca' option provides the path to the certificates for client
# authentication.
#
# TLS certificates are stored either in one or two files:
#
#   www.example.com.pem or www.example.com-{cert,key}.pem
#
# TLS certificates are loaded in alphabetical order and the first certificate
# is the default for clients which do not support SNI.
#
# The 'refresh' option can be set to specify the refresh interval for the TLS
# certificates. Client authentication certificates cannot be refreshed since
# Go does not provide a mechanism for that yet.
#
# The default refresh interval is 3 seconds and cannot be lower than 1 second
# to prevent busy loops. To load the certificates only once and disable
# automatic refreshing set 'refresh' to zero.
#
#   cs=<name>;type=path;cert=path/to/certs;clientca=path/to/clientcas;refresh=3s
#
# HTTP
#
# The http certificate source loads certificates from an HTTP/HTTPS server.
#
# The 'cert' option provides a URL to a text file which contains all files
# that should be loaded from this directory. The filenames follow the same
# rules as for the path source. The text file can be generated with:
#
#   ls -1 *.pem > list
#
# The 'clientca' option provides a URL for the client authentication
# certificates analogous to the 'cert' option.
#
# Authentication credentials can be provided in the URL as request parameter,
# as basic authentication parameters or through a header.
#
# The 'refresh' option can be set to specify the refresh interval for the TLS
# certificates. Client authentication certificates cannot be refreshed since
# Go does not provide a mechanism for that yet.
#
# The default refresh interval is 3 seconds and cannot be lower than 1 second
# to prevent busy loops. To load the certificates only once and disable
# automatic refreshing set 'refresh' to zero.
#
#   cs=<name>;type=http;cert=https://host.com/path/to/cert/list&token=123
#   cs=<name>;type=http;cert=https://user:[email protected]/path/to/cert/list
#   cs=<name>;type=http;cert=https://host.com/path/to/cert/list;hdr=Authorization: Bearer 1234
#
# Consul
#
# The consul certificate source loads certificates from consul.
#
# The 'cert' option provides a KV store URL where the the TLS certificates are
# stored.
#
# The 'clientca' option provides a URL to a path in the KV store where the the
# client authentication certificates are stored.
#
# The filenames follow the same rules as for the path source.
#
# The TLS certificates are updated automatically whenever the KV store
# changes. The client authentication certificates cannot be updated
# automatically since Go does not provide a mechanism for that yet.
#
#   cs=<name>;type=consul;cert=http://localhost:8500/v1/kv/path/to/cert&token=123
#
# Vault
#
# The Vault certificate store uses HashiCorp Vault as the certificate
# store.
#
# The 'cert' option provides the path to the TLS certificates and the
# 'clientca' option provides the path to the certificates for client
# authentication.
#
# The 'refresh' option can be set to specify the refresh interval for the TLS
# certificates. Client authentication certificates cannot be refreshed since
# Go does not provide a mechanism for that yet.
#
# The default refresh interval is 3 seconds and cannot be lower than 1 second
# to prevent busy loops. To load the certificates only once and disable
# automatic refreshing set 'refresh' to zero.
#
# The path to vault must be provided in the VAULT_ADDR environment
# variable. The token can be provided in the VAULT_TOKEN environment
# variable, or provided by using the Vault fetch token option.  By default the
# token is loaded once from the VAULT_TOKEN environment variable.  See Vault PKI for details.
#
#   cs=<name>;type=vault;cert=secret/fabio/certs
#
# Vault PKI
#
# The Vault PKI certificate store uses HashiCorp Vault's PKI backend to issue
# certificates on-demand.
#
# The 'cert' option provides a PKI backend path for issuing certificates. The
# 'clientca' option works in the same way as for the generic Vault source.
#
# The 'refresh' option determines how long before the expiration date
# certificates are re-issued. Values smaller than one hour are silently changed
# to one hour, which is also the default.
#
#   cs=<name>;type=vault-pki;cert=pki/issue/example-dot-com;refresh=24h;clientca=secret/fabio/client-certs
#
# This source will issue server certificates on-demand using the PKI backend
# and re-issue them 24 hours before they expire. The CA for client
# authentication is expected to be stored at secret/fabio/client-certs.
#
# 'vaultfetchtoken' enables fetching the vault token from a file on the filesystem or an environment
# variable at the Vault refresh interval.  If fetching the token from a file the 'file:[path]' syntax should be used,
# if fetching the token from an env variable, the 'env:[ENV]' syntax should be used.
#
#  cs=<name>;type=vault;cert=secret/fabio/certs;vaultfetchtoken=env:VAULT_TOKEN
#
# Common options
#
# All certificate stores support the following options:
#
#   caupgcn: Upgrade a self-signed client auth certificate with this common-name
#            to a CA certificate. Typically used for self-singed certificates
#            for the Amazon AWS Api Gateway certificates which do not have the
#            CA flag set which makes them unsuitable for client certificate
#            authentication in Go. For the AWS Api Gateway set this value
#            to 'ApiGateway' to allow client certificate authentication.
#            This replaces the deprecated parameter 'aws.apigw.cert.cn'
#            which was introduced in version 1.1.5.
#
# Examples:
#
#     # file based certificate source
#     proxy.cs = cs=some-name;type=file;cert=p/a-cert.pem;key=p/a-key.pem
#
#     # path based certificate source
#     proxy.cs = cs=some-name;type=path;path=path/to/certs
#
#     # HTTP certificate source
#     proxy.cs = cs=some-name;type=http;cert=https://user:pass@host:port/path/to/certs
#
#     # Consul certificate source
#     proxy.cs = cs=some-name;type=consul;cert=https://host:port/v1/kv/path/to/certs?token=abc123
#
#     # Vault certificate source
#     proxy.cs = cs=some-name;type=vault;cert=secret/fabio/certs
#
#     # Vault PKI certificate source
#     proxy.cs = cs=some-name;type=vault-pki;cert=pki/issue/example-dot-com
#
#     # Multiple certificate sources
#     proxy.cs = cs=srcA;type=path;path=path/to/certs,\
#                cs=srcB;type=http;cert=https://user:pass@host:port/path/to/certs
#
#     # path based certificate source for AWS Api Gateway
#     proxy.cs = cs=some-name;type=path;path=path/to/certs;clientca=path/to/clientcas;caupgcn=ApiGateway
#
# The default is
#
# proxy.cs =


# proxy.addr configures listeners.
#
# Each listener is configured with and address and a
# list of optional arguments in the form of
#
#   [host]:port;opt=arg;opt[=arg];...
#
# Each listener has a protocol which is configured
# with the 'proto' option for which it routes and
# forwards traffic.
#
# The supported protocols are:
#
#   * http for HTTP based protocols
#   * https for HTTPS based protocols
#   * tcp for a raw TCP proxy with or witout TLS support
#   * tcp+sni for an SNI aware TCP proxy
#   * tcp-dynamic for a consul driven TCP proxy
#
# If no 'proto' option is specified then the protocol
# is either 'http' or 'https' depending on whether a
# certificate source is configured via the 'cs' option
# which contains the name of the certificate source.
#
# The TCP+SNI proxy analyzes the ClientHello message
# of TLS connections to extract the server name
# extension and then forwards the encrypted traffic
# to the destination without decrypting the traffic.
#
# General options:
#
#   rt:          Sets the read timeout as a duration value (e.g. '3s')
#
#   wt:          Sets the write timeout as a duration value (e.g. '3s')
#
#   strictmatch: When set to 'true' the certificate source must provide
#                a certificate that matches the hostname for the connection
#                to be established. Otherwise, the first certificate is used
#                if no matching certificate was found. This matches the default
#                behavior of the Go TLS server implementation.
#
#   pxyproto:    When set to 'true' the listener will respect upstream v1
#                PROXY protocol headers.
#                NOTE: PROXY protocol was on by default from 1.1.3 to 1.5.10.
#                This changed to off when this option was introduced with
#                the 1.5.11 release.
#                For more information about the PROXY protocol, please see:
#                http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
#
#   pxytimeout:  Sets PROXY protocol header read timeout as a duration (e.g. '250ms').
#                This defaults to 250ms if not set when 'pxyproto' is enabled.
#
#   refresh:     Sets the refresh interval to check the route table for updates.
#                Used when 'tcp-dynamic' is enabled.
#
# TLS options:
#
#   tlsmin:      Sets the minimum TLS version for the handshake. This value
#                is one of [ssl30, tls10, tls11, tls12] or the corresponding
#                version number from https://golang.org/pkg/crypto/tls/#pkg-constants
#
#   tlsmax:      Sets the maximum TLS version for the handshake. See 'tlsmin'
#                for the format.
#
#   tlsciphers:  Sets the list of allowed ciphers for the handshake. The value
#                is a quoted comma-separated list of the hex cipher values or
#                the constant names from https://golang.org/pkg/crypto/tls/#pkg-constants,
#                e.g. "0xc00a,0xc02b" or "TLS_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA"
#
# Examples:
#
#     # HTTP listener on port 9999
#     proxy.addr = :9999
#
#     # HTTP listener on IPv4 with read timeout
#     proxy.addr = 1.2.3.4:9999;rt=3s
#
#     # HTTP listener on IPv6 with write timeout
#     proxy.addr = [2001:DB8::A/32]:9999;wt=5s
#
#     # Multiple listeners
#     proxy.addr = 1.2.3.4:9999;rt=3s,[2001:DB8::A/32]:9999;wt=5s
#
#     # HTTPS listener on port 443 with certificate source
#     proxy.addr = :443;cs=some-name
#
#     # HTTPS listener on port 443 with certificate source and TLS options
#     proxy.addr = :443;cs=some-name;tlsmin=tls10;tlsmax=tls11;tlsciphers="0xc00a,0xc02b"
#
#     # TCP listener on port 1234 with port routing
#     proxy.addr = :1234;proto=tcp
#
#     # TCP listener on port 443 with SNI routing
#     proxy.addr = :443;proto=tcp+sni
#
#     # TCP listeners using consul for config with 5 second refresh interval
#     proxy.addr = 0.0.0.0:0;proto=tcp-dynamic;refresh=5s
#
# The default is
#
proxy.addr = :9999
# proxy.addr = 0.0.0.0:9999;proto=tcp-dynamic;refresh=5s


# proxy.localip configures the ip address of the proxy which is added
# to the Header configured by header.clientip and to the 'Forwarded: by=' attribute.
#
# The local non-loopback address is detected during startup
# but can be overwritten with this property.
#
# The default is
#
# proxy.localip =


# proxy.strategy configures the load balancing strategy.
#
# rnd: pseudo-random distribution
# rr:  round-robin distribution
#
# "rnd" configures a pseudo-random distribution by using the microsecond
# fraction of the time of the request.
#
# "rr" configures a round-robin distribution.
#
# The default is
#
# proxy.strategy = rnd


# proxy.matcher configures the path matching algorithm.
#
# prefix: prefix matching
# glob:  glob matching
# iprefix: case-insensitive prefix matching
#
# The default is
#
# proxy.matcher = prefix


# proxy.noroutestatus configures the response code when no route was found.
#
# The default is
#
# proxy.noroutestatus = 404


# proxy.shutdownwait configures the time for a graceful shutdown.
#
# After a signal is caught the proxy will immediately suspend
# routing traffic and respond with a 503 Service Unavailable
# for the duration of the given period.
#
# The default is
#
# proxy.shutdownwait = 0s


# proxy.responseheadertimeout configures the response header timeout.
#
# This configures the ResponseHeaderTimeout of the http.Transport.
#
# The default is
#
# proxy.responseheadertimeout     = 0s


# proxy.keepalivetimeout configures the keep-alive timeout.
#
# This configures the KeepAliveTimeout of the network dialer.
#
# The default is
#
# proxy.keepalivetimeout     = 0s


# proxy.dialtimeout configures the connection timeout for
# outgoing connections.
#
# This configures the DialTimeout of the network dialer.
#
# The default is
#
# proxy.dialtimeout = 30s


# proxy.flushinterval configures periodic flushing of the
# response buffer for SSE (server-sent events) connections.
# They are detected when the 'Accept' header is
# 'text/event-stream'.
#
# The default is
#
# proxy.flushinterval = 1s


# proxy.globalflushinterval configures periodic flushing of the
# response buffer for non-SSE connections. By default it is not enabled.
#
# The default is
#
# proxy.globalflushinterval = 0


# proxy.maxconn configures the maximum number of cached
# incoming and outgoing connections.
#
# This configures the MaxIdleConnsPerHost of the http.Transport.
#
# The default is
#
# proxy.maxconn = 10000


# proxy.header.clientip configures the header for the request ip.
#
# The remoteIP is taken from http.Request.RemoteAddr.
#
# The default is
#
# proxy.header.clientip =


# proxy.header.tls configures the header to set for TLS connections.
#
# When set to a non-empty value the proxy will set this header on every
# TLS request to the value of ${proxy.header.tls.value}
#
# The default is
#
# proxy.header.tls =
# proxy.header.tls.value =


# proxy.header.requestid configures the header for the adding a unique request id.
# When set non-empty value the proxy will set this header on every request to the
# unique UUID value.
#
# The default is
#
# proxy.header.requestid =


# proxy.header.sts.maxage enables and configures the max-age of HSTS for TLS requests.
# When set greater than zero this enables the Strict-Transport-Security header
# and sets the max-age value in the header.
#
# The default is
#
# proxy.header.sts.maxage = 0


# proxy.header.sts.subdomains instructs HSTS to include subdomains.
# When set to true, the 'includeSubDomains' option will be added to
# the Strict-Transport-Security header.
#
# The default is
#
# proxy.header.sts.subdomains = false


# proxy.header.sts.preload instructs HSTS to include the preload directive.
# When set to true, the 'preload' option will be added to the
# Strict-Transport-Security header.
#
# Sending the preload directive from your site can have PERMANENT CONSEQUENCES
# and prevent users from accessing your site and any of its subdomains if you
# find you need to switch back to HTTP. Please read the details at
# https://hstspreload.org/#removal before sending the header with "preload".
#
# The default is
#
# proxy.header.sts.preload = false


# proxy.gzip.contenttype configures which responses should be compressed.
#
# By default, responses sent to the client are not compressed even if the
# client accepts compressed responses by setting the 'Accept-Encoding: gzip'
# header. By setting this value responses are compressed if the Content-Type
# header of the response matches and the response is not already compressed.
# The list of compressable content types is defined as a regular expression.
# The regular expression must follow the rules outlined in golang.org/pkg/regexp.
#
# A typical example is
#
# proxy.gzip.contenttype = ^(text/.*|application/(javascript|json|font-woff|xml)|.*\\+(json|xml))(;.*)?$
#
# The default is
#
# proxy.gzip.contenttype =

# proxy.auth configures one or more auth schemes.
#
# Each auth scheme is configured with a list of
# key/value options. Each source must have a unique
# name which can then be referred to in a routing
# rule.
#
#   name=<name>;type=<type>;opt=arg;opt[=arg];...
#
# The following types of auth schemes are available:
#
# Basic
#
# The basic auth scheme leverages http basic authentication using
# one htpasswd file which is loaded at startup and by default is cached until
# the service exits. However, it's possible to refresh htpasswd file
# periodically by setting the refresh interval with 'refresh' option.
#
# The 'file' option contains the path to the htpasswd file. The 'realm'
# option contains realm name (optional, default is the scheme name).
# The 'refresh' option can set the htpasswd file refresh interval. Minimal
# refresh interval is 1s to void busy loop.
# By default refresh is disabled i.e. set to zero.
#
#   name=<name>;type=basic;file=p/creds.htpasswd;realm=foo
#
# Examples
#
#   # single basic auth scheme
#
#   name=mybasicauth;type=basic;file=p/creds.htpasswd;
#
#   # single basic auth scheme with refresh interval set to 30 seconds
#
#   name=mybasicauth;type=basic;file=p/creds.htpasswd;refresh=30s
#
#   # basic auth with multiple schemes
#
#   proxy.auth = name=mybasicauth;type=basic;file=p/creds.htpasswd
#                name=myotherauth;type=basic;file=p/other-creds.htpasswd;realm=myrealm

# log.access.format configures the format of the access log.
#
# If the value is either 'common' or 'combined' then the logs are written in
# the Common Log Format or the Combined Log Format as defined below:
#
# 'common':   $remote_host - - [$time_common] "$request" $response_status $response_body_size
# 'combined': $remote_host - - [$time_common] "$request" $response_status $response_body_size "$header.Referer" "$header.User-Agent"
#
# Otherwise, the value is interpreted as a custom log format which is defined
# with the following parameters. Providing an empty format when logging is
# enabled is an error. To disable access logging leave the log.access.target
# value empty.
#
#   $header.<name>           - request http header (name: [a-zA-Z0-9-]+)
#   $remote_addr             - host:port of remote client
#   $remote_host             - host of remote client
#   $remote_port             - port of remote client
#   $request                 - request <method> <uri> <proto>
#   $request_args            - request query parameters
#   $request_host            - request host header (aka server name)
#   $request_method          - request method
#   $request_scheme          - request scheme
#   $request_uri             - request URI
#   $request_url             - request URL
#   $request_proto           - request protocol
#   $response_body_size      - response body size in bytes
#   $response_status         - response status code
#   $response_time_ms        - response time in S.sss format
#   $response_time_us        - response time in S.ssssss format
#   $response_time_ns        - response time in S.sssssssss format
#   $time_rfc3339            - log timestamp in YYYY-MM-DDTHH:MM:SSZ format
#   $time_rfc3339_ms         - log timestamp in YYYY-MM-DDTHH:MM:SS.sssZ format
#   $time_rfc3339_us         - log timestamp in YYYY-MM-DDTHH:MM:SS.ssssssZ format
#   $time_rfc3339_ns         - log timestamp in YYYY-MM-DDTHH:MM:SS.sssssssssZ format
#   $time_unix_ms            - log timestamp in unix epoch ms
#   $time_unix_us            - log timestamp in unix epoch us
#   $time_unix_ns            - log timestamp in unix epoch ns
#   $time_common             - log timestamp in DD/MMM/YYYY:HH:MM:SS -ZZZZ
#   $upstream_addr           - host:port of upstream server
#   $upstream_host           - host of upstream server
#   $upstream_port           - port of upstream server
#   $upstream_request_scheme - upstream request scheme
#   $upstream_request_uri    - upstream request URI
#   $upstream_request_url    - upstream request URL
#   $upstream_service        - name of the upstream service
#
# The default is
#
# log.access.format = common


# log.access.target configures where the access log is written to.
#
# Options are 'stdout'. If the value is empty no access log is written.
#
# The default is
#
log.access.target = stdout


# log.level configures the log level.
#
# Valid levels are TRACE, DEBUG, INFO, WARN, ERROR and FATAL.
#
# The default is
#
log.level = INFO


# log.routes.format configures the log output format of routing table updates.
#
# Changes to the routing table are written to the standard log. This option
# configures the output format:
#
# detail:   detailed routing table as ascii tree
# delta:    additions and deletions in config language
# all:      complete routing table in config language
#
# The default is
#
log.routes.format = delta


# registry.backend configures which backend is used.
# Supported backends are: consul, static, file, custom
# if custom is used fabio makes an api call to a remote system
# expecting the below json response
#   [
#    {
#       "cmd": "string",
#       "service": "string",
#       "src": "string",
#       "dest": "string",
#       "weight": float,
#       "tags": ["string"],
#       "opts": {"string":"string"}
#     }
#   ]
#
# The default is
#
# registry.backend = consul


# registry.timeout configures how long fabio tries to connect to the registry
# backend during startup.
#
# The default is
#
# registry.timeout = 10s


# registry.retry configures the interval with which fabio tries to
# connect to the registry during startup.
#
# The default is
#
# registry.retry = 500ms


# registry.static.routes configures a static routing table.
#
# Example:
#
#     registry.static.routes = \
#       route add svc / http://1.2.3.4:5000/
#
# The default is
#
# registry.static.routes =


# registry.static.noroutehtmlpath configures the KV path for the HTML of the
# noroutes page.
#
# The default is
#
# registry.static.noroutehtmlpath =


# registry.file.path configures a file based routing table.
# The value configures the path to the file with the routing table.
#
# The default is
#
# registry.file.path =


# registry.file.noroutehtmlpath configures the KV path for the HTML of the
# noroutes page.
#
# The default is
#
# registry.file.noroutehtmlpath =


# registry.consul.addr configures the address of the consul agent to connect to.
#
# The default is
#
# registry.consul.addr = localhost:8500


# registry.consul.token configures the acl token for consul.
#
# The default is
#
# registry.consul.token =


# registry.consul.tls.keyfile the path to the TLS certificate private key used for Consul communication.
#
# This is the full path to the TLS private key while using TLS transport to
# communicate with Consul
#
# The default is
#
# registry.consul.tls.keyfile =

# registry.consul.tls.certfile the path to the TLS certificate used for Consul communication.
#
# This is the full path to the TLS certificate while using TLS transport to
# communicate with Consul
#
# The default is
#
# registry.consul.tls.certfile =


# registry.consul.tls.cafile the path to the ca certificate used for Consul communication.
#
# This is the full path to the CA certificate while using TLS transport to
# communicate with Consul
#
# The default is
#
# registry.consul.tls.cafile =

# registry.consul.tls.capath the path to the folder containing CA certificates.
#
# This is the full path to the folder with CA certificates while using TLS transport to
# communicate with Consul
#
# The default is
#
# registry.consul.tls.capath =


# registry.consul.tls.insecureskipverify enable SSL verification with Consul.
#
# registry.consul.tls.insecureskipverify enables or disables SSL verification while using TLS transport to
# communicate with Consul
#
# The default is
#
# registry.consul.tls.insecureskipverify = false


# registry.consul.kvpath configures the KV path for manual routes.
#
# The consul KV path is watched for changes which get appended to
# the routing table. This allows for manual overrides and weighted
# round-robin routes. The key itself (e.g. fabio/config) and all
# subkeys (e.g. fabio/config/foo and fabio/config/bar) are combined
# in alphabetical order.
#
# The default is
#
# registry.consul.kvpath = /fabio/config


# registry.consul.noroutehtmlpath configures the KV path for the HTML of the
# noroutes page.
#
# The consul KV path is watched for changes.
#
# The default is
#
# registry.consul.noroutehtmlpath = /fabio/noroute.html

# registry.consul.service.status configures the valid service status
# values for services included in the routing table.
#
# The values are a comma separated list of
# "passing", "warning", "critical" and "unknown"
#
# The default is
#
# registry.consul.service.status = passing


# registry.consul.tagprefix configures the prefix for tags which define routes.
#
# Services which define routes publish one or more tags with host/path
# routes which they serve. These tags must have this prefix to be
# recognized as routes.
#
# The default is
#
# registry.consul.tagprefix = urlprefix-


# registry.consul.register.enabled configures whether fabio registers itself in consul.
#
# Fabio will register itself in consul only if this value is set to "true" which
# is the default. To disable registration set it to any other value, e.g. "false"
#
# The default is
#
# registry.consul.register.enabled = true


# registry.consul.register.addr configures the address for the service registration.
#
# Fabio registers itself in consul with this host:port address.
# It must point to the UI/API endpoint configured by ui.addr and defaults to its
# value.
#
# The default is
#
# registry.consul.register.addr = :9998


# registry.consul.register.name configures the name for the service registration.
#
# Fabio registers itself in consul under this service name.
#
# The default is
#
# registry.consul.register.name = fabio


# registry.consul.register.tags configures the tags for the service registration.
#
# Fabio registers itself with these tags. You can provide a comma separated list of tags.
#
# The default is
#
# registry.consul.register.tags =


# registry.consul.register.checkInterval configures the interval for the health check.
#
# Fabio registers an http health check on http(s)://${ui.addr}/health
# and this value tells consul how often to check it.
#
# The default is
#
# registry.consul.register.checkInterval = 1s


# registry.consul.register.checkTimeout configures the timeout for the health check.
#
# Fabio registers an http health check on http(s)://${ui.addr}/health
# and this value tells consul how long to wait for a response.
#
# The default is
#
# registry.consul.register.checkTimeout = 3s


# registry.consul.register.checkTLSSkipVerify configures TLS verification for the health check.
#
# Fabio registers an http health check on http(s)://${ui.addr}/health
# and this value tells consul to skip TLS certificate validation for
# https checks.
#
# The default is
#
# registry.consul.register.checkTLSSkipVerify = false


# registry.consul.register.checkDeregisterCriticalServiceAfter configures
# automatic deregistration of a service after the health check is critical for
# this length of time.
#
# Fabio registers an http health check on http(s)://${ui.addr}/health
# and this value tells consul to deregister the associated service if the check
# is critical for the specified duration.
#
# The default is
#
# registry.consul.register.checkDeregisterCriticalServiceAfter = 90m


# registry.consul.checksRequired configures how many health checks
# must pass in order for fabio to consider a service available.
#
# Possible values are:
#  one: at least one health check must pass
#  all: all health checks must pass
#
# The default is
#
# registry.consul.checksRequired = one


# registry.consul.serviceMonitors configures the concurrency for
# route updates. Fabio will make up to the configured number of
# concurrent calls to Consul to fetch status data for route
# updates.
#
# The default is
#
# registry.consul.serviceMonitors = 1


# registry.custom.host configures the host:port for fabio to make the API call
#
# The default is
#
# registry.custom.host =


# registry.custom.scheme configures the scheme use to make the API call
# must be one of http, https
#
# The default is
#
# registry.custom.scheme = https


# registry.custom.checkTLSSkipVerify disables the TLS validation for the API call
#
# The default is
#
# registry.custom.checkTLSSkipVerify = false


# registry.custom.timeout controls the timeout for the API call
#
# The default is
#
# registry.custom.timeout = 5s


# registry.custom.pollinginterval is the length of time between API calls
#
# The default is
#
#registry.custom.pollinginterval = 10s


# registry.custom.path is the path used in the custom back end API Call
#
# The path does not need to contain the initial '/'
#
# Example:
#
#     registry.custom.path = api/v1/
#
# The default is
#
# registry.custom.path =

# registry.custom.queryparams is the query parameters used in the custom back
# end API Call
#
# Multiple query parameters should be separated with an &
#
# Example:
#
#     registry.custom.queryparams = foo=bar&bar=foo
#
# The default is
#
# registry.custom.queryparams =


# glob.matching.disabled disables glob matching on route lookups
# If glob matching is enabled there is a performance decrease
# for every route lookup.  At a large number of services (> 500) this
# can have a significant impact on performance. If glob matching is disabled
# Fabio performs a static string compare for route lookups.
#
# The default is
#
# glob.matching.disabled = false


# metrics.target configures the backend the metrics values are
# sent to.
#
# Possible values are:
#  <empty>:  do not report metrics
#  stdout:   report metrics to stdout
#  graphite: report metrics to Graphite on ${metrics.graphite.addr}
#  statsd: report metrics to StatsD on ${metrics.statsd.addr}
#  circonus: report metrics to Circonus (http://circonus.com/)
#
# The default is
#
# metrics.target =


# metrics.prefix configures the template for the prefix of all reported metrics.
#
# Each metric has a unique name which is hard-coded to
#
#    prefix.service.host.path.target-addr
#
# The value is expanded by the text/template package and provides
# the following variables:
#
#  - Hostname:  the Hostname of the server
#  - Exec:      the executable name of application
#
# The following additional functions are defined:
#
#  - clean:     lowercase value and replace '.' and ':' with '_'
#
# Template may include regular string parts to customize final prefix
#
# Example:
#
#  Server hostname: test-001.something.com
#  Binary executable name: fabio
#
#  The template variables are:
#
#  .Hostname =  test-001.something.com
#  .Exec = fabio
#
# which results to the following prefix string when using the
# default template:
#
#  test-001_something_com.fabio
#
# The default is
#
# metrics.prefix = {{clean .Hostname}}.{{clean .Exec}}


# metrics.names configures the template for the route metric names.
# The value is expanded by the text/template package and provides
# the following variables:
#
#  - Service:   the service name
#  - Host:      the host part of the URL prefix
#  - Path:      the path part of the URL prefix
#  - TargetURL: the URL of the target
#
# The following additional functions are defined:
#
#  - clean:     lowercase value and replace '.' and ':' with '_'
#
# Given a route rule of
#
#  route add testservice www.example.com/ http://10.1.2.3:12345/
#
# the template variables are:
#
#  .Service = testservice
#  .Host = www.example.com
#  .Path  = /
#  .TargetURL.Host = 10.1.2.3:12345
#
# which results to the following metric name when using the
# default template:
#
#  testservice.www_example_com./.10_1_2_3_12345
#
# The default is
#
# metrics.names = {{clean .Service}}.{{clean .Host}}.{{clean .Path}}.{{clean .TargetURL.Host}}


# metrics.interval configures the interval in which metrics are
# reported.
#
# The default is
#
# metrics.interval = 30s


# metrics.timeout configures how long fabio tries to connect to the metrics
# backend during startup.
#
# The default is
#
# metrics.timeout = 10s


# metrics.retry configures the interval with which fabio tries to
# connect to the metrics backend during startup.
#
# The default is
#
# metrics.retry = 500ms


# metrics.graphite.addr configures the host:port of the Graphite
# server. This is required when ${metrics.target} is set to "graphite".
#
# The default is
#
# metrics.graphite.addr =


# metrics.statsd.addr configures the host:port of the StatsD
# server. This is required when ${metrics.target} is set to "statsd".
#
# The default is
#
# metrics.statsd.addr =


# metrics.circonus.apikey configures the API token key to use when
# submitting metrics to Circonus. See: https://login.circonus.com/user/tokens
# This is optional when ${metrics.target} is set to "circonus" but
# ${metrics.circonus.submissionurl is specified}.
#
# The default is
#
# metrics.circonus.apikey =


# metrics.circonus.submissionurl configures a specific check submission url
# for a Check API object of a previously created HTTPTRAP check
# This is optional when ${metrics.target} is set to "circonus" but
# ${metrics.circonus.apikey is specified}.
# #### Example
#
# `http://127.0.0.1:2609/write/fabio`
#
# The default is
#
# metrics.circonus.submissionurl =


# metrics.circonus.apiapp configures the API token app to use when
# submitting metrics to Circonus. See: https://login.circonus.com/user/tokens
# This is optional when ${metrics.target} is set to "circonus".
#
# The default is
#
# metrics.circonus.apiapp = fabio


# metrics.circonus.apiurl configures the API URL to use when
# submitting metrics to Circonus. https://api.circonus.com/v2/
# will be used if no specific URL is provided.
# This is optional when ${metrics.target} is set to "circonus".
#
# The default is
#
# metrics.circonus.apiurl =


# metrics.circonus.brokerid configures a specific broker to use when
# creating a check for submitting metrics to Circonus.
# This is optional when ${metrics.target} is set to "circonus".
# Optional for public brokers, required for Inside brokers.
# Only applicable if a check is being created.
#
# The default is
#
# metrics.circonus.brokerid =


# metrics.circonus.checkid configures a specific check to use when
# submitting metrics to Circonus.
# This is optional when ${metrics.target} is set to "circonus".
# An attempt will be made to search for a previously created check,
# if no applicable check is found, one will be created.
#
# The default is
#
# metrics.circonus.checkid =


# runtime.gogc configures GOGC (the GC target percentage).
#
# Setting runtime.gogc is equivalent to setting the GOGC
# environment variable which also takes precedence over
# the value from the config file.
#
# Increasing this value means fewer but longer GC cycles
# since there is more garbage to collect.
#
# The default of GOGC=100 works for Go 1.4 but shows
# a significant performance drop for Go 1.5 since the
# concurrent GC kicks in more often.
#
# During benchmarking I have found the following values
# to work for my setup and for now I consider them sane
# defaults for both Go 1.4 and Go 1.5.
#
# GOGC=100: Go 1.5 40% slower than Go 1.4
# GOGC=200: Go 1.5 == Go 1.4 with GOGC=100 (default)
# GOGC=800: both Go 1.4 and 1.5 significantly faster (40%/go1.4, 100%/go1.5)
#
# The default is
#
# runtime.gogc = 800


# runtime.gomaxprocs configures GOMAXPROCS.
#
# Setting runtime.gomaxprocs is equivalent to setting the GOMAXPROCS
# environment variable which also takes precedence over
# the value from the config file.
#
# If runtime.gomaxprocs < 0 then all CPU cores are used.
#
# The default is
#
# runtime.gomaxprocs = -1


# ui.access configures the access mode for the UI.
#
#  ro:  read-only access
#  rw:  read-write access
#
# The default is
#
# ui.access = rw


# ui.addr configures the address the UI is listening on.
# The listener uses the same syntax as proxy.addr but
# supports only a single listener. To enable HTTPS
# configure a certificate source. You should use
# a different certificate source than the one you
# use for the external connections, e.g. 'cs=ui'.
#
# The default is
#
# ui.addr = :9998


# ui.color configures the background color of the UI.
# Color names are from http://materializecss.com/color.html
#
# The default is
#
# ui.color = light-green


# ui.title configures an optional title for the UI.
#
# The default is
#
# ui.title =


# Open Trace Configuration Currently supports ZipKin Collector
# tracing.TracingEnabled enables/disables  Open Tracing in Fabio.  Bool value true/false
#
# The default is
#
# tracing.TracingEnabled = false

# tracing.CollectorType sets what type of collector is used.
# Currently only two types are supported http and kafka
#
# http: sets collector type to http tracing.ConnectString must also be set
# kafka: sets collector type to emit via kafka.  tracing.Topic must also be set
#
# The default is
#
# tracing.CollectorType = http


# tracing.ConnectString sets the connection string per connection type.
# If tracing.CollectorType = http tracing.ConnectString should be
# http://URL:PORT where URL is the URL of your collector and PORT is the TCP Port
# it is listening on
#
# If tracing.CollectorType = kafka tracing.ConnectString should be
# HOSTNAME:PORT of your kafka broker
# tracing.Topic must also be set
#
# The default is
#
# tracing.ConnectString = http://localhost:9411/api/v1/spans


# tracing.ServiceName sets the service name used in reporting span information
#
# The default is
#
# tracing.ServiceName = Fabiolb


# tracing.Topic sets the Topic String used if tracing.CollectorType is kafka and
# tracing.ConnectSting is set to a kafka broker
#
# The default is
#
# tracing.Topic = Fabiolb-Kafka-Topic


# tracing.SamplerRate is the rate at which opentrace span data will be collected and sent
# If SamplerRate is <= 0 Never sample
# If SamplerRate is >= 1.0 always sample
# Values between 0 and 1 will be the percentage in decimal form
# Example a value of .50 will be 50% sample rate
#
# The default is
# tracing.SamplerRate = -1


# tracing.SpanHost sets host information.
# This is used to specify additional information when sending spans to a collector
#
# The default is
# tracing.SpanHost = localhost:9998