Home of N3BBQ
  • About
  • RIP
  • All posts

Templating NGiNX Configs with Ansible - Thu, Oct 22, 2020

Templating NGiNX Configs with Ansible

Today I started down the path of trying to template out the Nginx load balancer configs for our systems. I wanted to find out how others were building their templates out of yaml configs. There were not very many documents on it, so I had to figure it out myself.

Lets see what a basic config file in YAML format would look like in this example.

filename: test123.conf
template: generic_site_template.j2
upstream:
  name: cms
  servers:
      - webserver1.example.local:
          weight: 10
      - webserver2.example.local:
          fail_timeout: 2s
          weight: 12
      - webserver3.example.local:
          backup:
  port: 443
  options:
    zonesize: 256k
    sticky: sticky cookie srv_id expires=1h domain=.example.local path=/
    balancing: least_conn
    keepalive: 32
    ntlm: 
    queue:
      number: 100
      timeout: 120
server:
  ssl:
    ciphers: "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA HIGH !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
    cache: "shared:SSL:20m"
    timeout: 24h
    enabled: true
    ssl_certificate: /etc/ssl/www/www.example.local.crt
    ssl_certificate_key: /etc/ssl/www/www.example.local.key
  server_name: www.example.local
  logging:
    access: /var/log/nginx/www_access.log
    error: /var/log/nginx/www_error.log
    syslog: 172.20.20.20
  health_check: health_check match=server_ok passes=2
  options:
    gzip:
    max_body_size: 20M
    keepalive:
      requests: 10000
      timeout: 300s
    proxy:
      tcp:
      sni:
      proxy_host: www.example.local
      headers:
        connection:
        client:
      timeouts:
        connect: 300s
        send: 300s
        read: 300s

When I import this as include_vars setting the name as nginx_template, I can then run a it through the template I made.

{# ################# Upstream Block  ################# #}
{% if 'upstream' in nginx_template %}
upstream {{ nginx_template.upstream.name }} {
    zone {{ nginx_template.upstream.name }} {{ nginx_template.upstream.options.zonesize | default('512k', true) }};
    {{ nginx_template.upstream.options.balancing | default('least_conn', true) }};
{% for server in nginx_template.upstream.servers %}
{% for key, value in server.items() %}
    server {{ key }}:{{ nginx_template.upstream.port }}{% if value != None and 'weight' in value %} weight={{ value.weight }}{% endif %}{% if value != None and 'fail_timeout' in value %} fail_timeout={{ value.fail_timeout }}{% endif %}{% if value != None and 'backup' in value %} backup{% endif %};
{% endfor %}
{% endfor %}
{% if 'sticky' in nginx_template.upstream.options %}
    {{ nginx_template.upstream.options.sticky }};
{% endif %}
{% if 'keepalive' in nginx_template.upstream.options %}
    keepalive {{ nginx_template.upstream.options.keepalive }};
{% endif %}
{% if 'queue' in nginx_template.upstream.options %}
    queue {{ nginx_template.upstream.options.queue.number | default("100") }} timeout={{ nginx_template.upstream.options.queue.timeout | default(120) }};
{% endif %}
{% if 'ntlm' in nginx_template.upstream.options %}
    ntlm;
{% endif %}
}
{% endif %}

{# ################# Server with SSL  ################# #}
{% if 'ssl' in nginx_template.server %}
server {
    listen 80;
    server_name {{ nginx_template.server.server_name | default('default', true) }};
    return 301 https://$server_name$request_uri;
}
server {
    listen {{ nginx_template.server.port | default('443') }} ssl;
    server_name {{ nginx_template.server.server_name | default('default', true) }};

    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "{{ nginx_template.server.ssl.ciphers | default ('EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA HIGH !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS') }}";
    ssl_session_cache {{ nginx_template.server.ssl.cache | default("shared:SSL:10m") }};
    ssl_session_timeout {{ nginx_template.server.ssl.timeout | default("24h") }};
    ssl_certificate {{ nginx_template.server.ssl.ssl_certificate }};
    ssl_certificate_key {{ nginx_template.server.ssl.ssl_certificate_key }};
{% endif %}

{# ################# Server without SSL ################# #}
{% if 'ssl' not in nginx_template.server %}
server {
    listen {{ nginx_template.server.port | default('80') }};
{% if 'tcp' not in nginx_template.server.options.proxy %}
    server_name {{ nginx_template.server.server_name | default('default', true) }};
{% endif %}
{% endif %}
{% if 'gzip' in nginx_template.server.options %}
    gzip on;
    gzip_types text/plain text/css text/xml application/javascript application/x-javascript application/xml application/xml+rss application/emacscript application/json image/svg+xml;
    gzip_proxied no-cache no-store private expired auth;
    gzip_min_length 1000;
{% endif %}
{% if 'headers' in nginx_template.server.options %}
    add_header X-Content-Type-Options "nosniff";
    add_header X-Forwarded-Proto "https";
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=631138519";
{% endif %}
{% if 'access' in nginx_template.server.logging %}
    access_log  {{ nginx_template.server.logging.access }}  main;
{% endif %}
{% if 'error' in nginx_template.server.logging %}
    error_log {{ nginx_template.server.logging.error }};
{% endif %}
{% if 'syslog' in nginx_template.server.logging %}
    access_log syslog:server={{ nginx_template.server.logging.syslog }},facility=local7,tag=nginx,severity=info;
{% endif %}
{% if 'tcp' not in nginx_template.server.options.proxy %}
    location / {
{% endif %}
{% if 'timeouts' in nginx_template.server.options.proxy %}
{% if 'connect' in nginx_template.server.options.proxy.timeouts %}
        proxy_connect_timeout {{ nginx_template.server.options.proxy.timeouts.connect | default("5s") }};
{% endif %}
{% if 'send' in nginx_template.server.options.proxy.timeouts %}
        proxy_send_timeout {{ nginx_template.server.options.proxy.timeouts.send | default("300s") }};
{% endif %}
{% if 'read' in nginx_template.server.options.proxy.timeouts %}
        proxy_read_timeout {{ nginx_template.server.options.proxy.timeouts.read | default("300s") }};
{% endif %}
{% endif %}
        proxy_pass {% if 'tcp' not in nginx_template.server.options.proxy %}https://{% endif %}{{ nginx_template.upstream.name }};
{% if 'tcp' not in nginx_template.server.options.proxy %}
        proxy_http_version 1.1;
{% if 'sni' in nginx_template.server.options.proxy %}
        proxy_ssl_server_name on;
        proxy_ssl_name {{ nginx_template.server.options.proxy.proxy_host | default("$host", true) }};
{% endif %}
{% if 'headers' in nginx_template.server.options.proxy %}
{% if 'connection' in nginx_template.server.options.proxy.headers %}
        proxy_set_header Host {{ nginx_template.server.options.proxy.proxy_host | default("$host", true) }};
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade ";
{% endif %}
{% if 'client' in nginx_template.server.options.proxy.headers %}
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
{% endif %}
{% endif %}
    }
{% endif %}
}

This gives me configs for that site. This works out great so we can make a bunch of yml files with our configs, and loop through them to generate our configs when we make a small change for the sites.

Back to Home


hugo.386 theme by Max le Fou | © Emma Harris 2020 | n3bbq | Built on Hugo