When managing multiple Nginx site configurations through Ansible, validating individual site configs presents unique challenges. Unlike the main nginx.conf
which is a complete configuration file, site-specific configs are partial fragments that need to be wrapped in proper context for validation.
# This works for the main config
validate="/usr/sbin/nginx -c %s -t"
# But fails for site configs because they lack http{} context
server {
listen 80;
server_name example.com;
# ... site configuration
}
Here's a complete Ansible solution that creates temporary validation contexts:
- name: Validate site configs before deployment
block:
- name: Create temporary validation wrapper
template:
src: nginx-validation-wrapper.j2
dest: "/tmp/{{ item.name }}.validate.conf"
mode: 0644
with_items: sites
vars:
config_path: "/etc/nginx/conf.d/{{ item.name }}.conf"
- name: Validate site configs
command: "/usr/sbin/nginx -t -c /tmp/{{ item.name }}.validate.conf"
register: validation_result
ignore_errors: yes
changed_when: false
with_items: sites
- name: Fail if validation errors exist
fail:
msg: "Nginx config validation failed: {{ validation_result.stderr }}"
when: validation_result.rc != 0
with_items: sites
Create nginx-validation-wrapper.j2
with this content:
events {
worker_connections 1024;
}
http {
include {{ config_path }};
}
Modify your original config deployment to include validation:
- name: Deploy site nginx config
template:
src: "nginx-site.conf.j2"
dest: "/etc/nginx/conf.d/{{ item.name }}.conf"
owner: root
group: root
mode: 0444
with_items: sites
notify: restart nginx
# Only proceed after validation succeeds
when: validation_result.rc == 0
For complex setups with included files:
http {
include /etc/nginx/mime.types;
include /etc/nginx/conf.d/*.conf;
include {{ config_path }};
}
This ensures all necessary context exists during validation while still testing the specific config file.
For better performance in large environments:
- name: Batch validate all site configs
command: "/usr/sbin/nginx -t -c /tmp/nginx-validation.conf"
vars:
config_content: |
events { worker_connections 1024; }
http {
{% for site in sites %}
include /etc/nginx/conf.d/{{ site.name }}.conf;
{% endfor %}
}
When managing Nginx configurations through Ansible, we often face a validation gap with site-specific configs. While the main nginx.conf
can be validated using nginx -t -c %s
, individual site configurations pose a special challenge because:
- They require being wrapped in
http {}
context to pass syntax check - Traditional validation methods treat them as incomplete fragments
- Ansible's template module executes validation before file placement
Here's a robust approach I've implemented in production environments:
- name: Validate site configs with proper context
template:
src: "nginx-site.conf.j2"
dest: "/tmp/{{ item.name }}.conf.tmp"
validate: "/bin/bash -c 'echo \"http { $(cat %s) }\" > %s.ctx && /usr/sbin/nginx -t -c %s.ctx'"
with_items: sites
register: validation_result
check_mode: yes
changed_when: false
- name: Deploy validated configs
template:
src: "nginx-site.conf.j2"
dest: "/etc/nginx/conf.d/{{ item.name }}.conf"
owner: root
group: root
mode: "0444"
with_items: sites
when: validation_result is success
notify: restart nginx
The solution works through several key steps:
- Temporary File Creation: First creates a temp file with the raw config
- Context Wrapping: Uses bash to wrap the content in http{} block
- Syntax Check: Validates the wrapped configuration
- Safe Deployment: Only proceeds with actual deployment after validation
For more complex scenarios, consider these enhancements:
# For environments with custom Nginx paths
validate: "/bin/bash -c 'NGINX=$(which nginx); echo \"http { $(cat %s) }\" > %s.ctx && $NGINX -t -c %s.ctx'"
# Adding timestamped validation
validate: "/bin/bash -c 'TS=$(date +%s); echo \"http { $(cat %s) }\" > /tmp/nginx-val-\"$TS\".conf && nginx -t -c /tmp/nginx-val-\"$TS\".conf && rm -f /tmp/nginx-val-\"$TS\".conf'"
To properly handle validation errors in your playbook:
- name: Validate configurations
# ... previous validation task ...
- name: Fail if validation errors
fail:
msg: "Nginx configuration validation failed"
when: validation_result is failed
- name: Cleanup temp files on success
file:
path: "/tmp/{{ item.name }}.conf.tmp"
state: absent
with_items: sites
when: validation_result is success