nginxinc / ansible-role-nginx-config Goto Github PK
View Code? Open in Web Editor NEWAnsible role for configuring NGINX
Home Page: https://galaxy.ansible.com/nginxinc/nginx_config
License: Apache License 2.0
Ansible role for configuring NGINX
Home Page: https://galaxy.ansible.com/nginxinc/nginx_config
License: Apache License 2.0
Is your feature request related to a problem? Please describe.
Now that module related installation tasks live in https://github.com/nginxinc/ansible-role-nginx, it makes little sense to keep module related templating working as it does right now where both the installation and configuration tasks live side by side.
Describe the solution you'd like
A better way to implement module templating would be to let users use a load_modules
list variable.
Describe alternatives you've considered
A different alternative would be to keep adding module specific templating variables (like they exist right now), but using a load_modules
list variable removes the need to keep implementing new module specific templates every time a new module becomes available.
Additional context
Some more context is available here #13
Is your feature request related to a problem? Please describe.
The default template should use plural variable name when dealing with proxy_set_header and proxy_hide_heaader.
Today, there is proxy_hide_headers and proxy_set_header
Even though one uses hash and the other is a simple array, it should be expressed as plural rabble names.
Describe the solution you'd like
We should lookup for proxy_set_headers
in the template and the defaults
Describe the bug
Role fails when hitting Ensure NGINX proxy cache directories exist
task despite skip_missing: true
.
To reproduce
Steps to reproduce the behavior:
nginx_config_http_template
, without any proxy_cache{"msg": "subelements lookup expects a dictionary, got 'None'"}
Expected behavior
The role shouldn't fail on cache directory check when proxy cache isn't configured/used.
Your environment:
Describe the bug
Having the stub_status module served via its own HTTP server on port 80 and without a server_name by default can give odd behaviour.
Having another HTTP host set as default_server isn't enough either to guarantee the separation.
The allow/deny statements should also be moved out of the /nginx_status location to the server block.
To reproduce
Steps to reproduce the behavior:
nginx_status_enable
default_server
).Expected behavior
The status page should by default be served in a context that does not conflict with any other port 80 listener deployed.
So either on a different port, or a location within an existing server block.
Your environment:
Is your feature request related to a problem? Please describe.
My problem was i wanted a way to enable gzip with some options on the default nginx.conf that this playbook creates but ididn't find such an option or something that i could do with the default nginx.conf except copy and add my own gzip headers/options.
Describe the solution you'd like
Adding a template option to enable gzip without creating a custom nginx.conf.j2 template.
Workaround
Creating my own nginx.conf that kinda has gzip enabled with some modifications.
Its not really a great deal but would ofcourse be a nice feature.
Here a bit of templated code i did really as an example
{% if nginx_config_main_template.http_settings.gzip %}
gzip on;
{% if nginx_config_main_template.http_settings.gzip.vary %}
gzip_vary on;
{% endif %}
{% if nginx_config_main_template.http_settings.gzip.min_length %}
gzip_min_length {{ nginx_config_main_template.http_settings.gzip.min_length }};
{% endif %}
{% if nginx_config_main_template.http_settings.gzip.proxied is defined and nginx_config_main_template.http_settings.gzip.proxied | length %}
gzip_proxied {{ nginx_config_main_template.http_settings.gzip.proxied }};
{% endif %}
{% if nginx_config_main_template.http_settings.gzip.types is defined and nginx_config_main_template.http_settings.gzip.types | length %}
gzip_types {{ nginx_config_main_template.http_settings.gzip.types }};
{% endif %}
{% if nginx_config_main_template.http_settings.gzip.disable %}
gzip_disable {{ nginx_config_main_template.http_settings.gzip.disable }}
{% endif %}
{% else %}
#gzip on;
{% endif %}
In the default scenario in molecule test is (see here) a rewrites
option configured. But in the latest molecule output on main branch, you can not find this entry in the generated /etc/nginx/conf.d/default.conf
(see here).
I also tested this locally and in all my tests (with molecule), I did not get it working to have a rewrite option in the config.
Run locally molecule test -s default
Having a rewrite
entry in the generated config, e.g. in server context:
server {
...
rewrite (.*).html(.*) $1$2 last;
...
}
Test with debian-buster (docker) molecule the default scenario.
I guess the changes in #189 are not covering all sequences. After changing this line
{% for rewrite in rewrite['rewrites'] if (rewrite['rewrites'] is sequence and rewrite['rewrites'] is not string) %}
to that:
{% for rewrite in rewrite['rewrites'] if (rewrite['rewrites'] is not mapping and rewrite['rewrites'] is not string) %}
the molecule test (I tested it only on debian-buster) was still good and output of the task [ansible-role-nginx-config : Print NGINX config] shows me the rewrite option in the config.
When running this role in check mode with selinux enabled, this role will alway report a change.
With nginx_selinux_enforcing
set to true
, run the role, then run the role again with --check.
No changes identified when running ansible in check mode.
Based on templates/http/proxy.j2 read_timeout should be boolean. In that case, proxy_read_timeout is set as on/off. Seems like it doesn't make sense and the deployment fails.
Steps to reproduce the behavior:
nginx: [emerg] \“proxy_read_timeout\” directive invalid value in /etc/nginx/conf.d/default.conf
Directive syntax: proxy_read_timeout time;
Hello!
There is no "include /etc/nginx/mime.types;" in default configs.
Only text/html is allowed.
So even a simple WordPress site doesn't work.
js/css don't work.
I spent a whole day to investigate that.
It would be better to keep original nginx.cfg (from nginx) in default setup.
It is not only possible, but very likely, that at some point when developing a playbook with this role, the role variables used will generate invalid main and/or http config files. The problem is that once the config files on the controlled host are bad, you cannot run the config role without encountering errors in the "Register NGINX Config" task, or without manual intervention to edit the files on the controlled host to make them good. It would be useful for there to be variables that allowed users to "force" the repushing of newly-generated config files (from changed role variables), i.e. skip the check config step. I think it would be even better if the config is not checked until after it is regenerated on the controlled host.
I'm using the nginxinc (open source, core) collection v0.1.3.
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
Describe the solution you'd like
A clear and concise description of what you want to happen.
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Additional context
Add any other context or screenshots about the feature request here.
Is your feature request related to a problem? Please describe.
i have an infrastructure that have production applications use grpc and currently automation for them is able to be done only by using a custom template.
so this is the problem - the only way to automate grpc with nginx is to use custom options which is barely readable and hard to support in that case or though making your own template.
Describe the solution you'd like
i would like nginx role to add an options to template to use grpc directives from grpc module https://nginx.org/en/docs/http/ngx_http_grpc_module.html#directives
Describe alternatives you've considered
have separate template specifically for grpc but it complicates things since it is still a part of 'http'
Additional context
how would I insert an if
statement such as:
if ($request_method = POST) {
return 405;
}
in the server
stanza? Thanks!
Is your feature request related to a problem? Please describe.
The current default template doesn't support the backup option on the server line.
Feature as described in Nginx doc
Describe the solution you'd like
Add backup as a boolean in the template
It should be implemented like item.value.upstreams[upstream].servers[server].down
already is.
A clear and concise description of what the problem is. Ex. I'm always frustrated when ...
I've been running reverse proxies and am finally getting better at the various configurations. Now I have a server behind the proxy that handles ssl itself on 443 so I need my reverse proxy to simply pass that connection through unchanged based on the server_name.
Problem = (either no example code) | (no community forum to ask questions) | (I really don't understand how to learn this myself from the source)
A clear and concise description of what you want to happen.
I think that the stream template is what I want. Can we get a sample of how to instantiate a server block for streams?
Is there a forum to ask these types of questions?
A clear and concise description of any alternative solutions or features you've considered.
Add any other context or screenshots about the feature request here.
I am trying to execute the following playbook
---
- name: Basic setup
hosts: gates
collections:
- nginxinc.nginx_core
tasks:
- name: Install NGINX
include_role:
name: nginx
- name: Configure NGINX
include_role:
name: nginx_config
vars:
nginx_config_debug_output: true
nginx_config_cleanup: true
nginx_config_cleanup_paths:
- directory:
- /etc/nginx/conf.d
recurse: false
nginx_config_cleanup_files:
- /etc/nginx/conf.d/default.conf
nginx_config_main_template_enable: false
nginx_config_main_template:
template_file: nginx.conf.j2
conf_file_name: nginx.conf
conf_file_location: /etc/nginx/
user: nginx
worker_processes: auto
worker_rlimit_nofile: 1024
pid: /var/run/nginx.pid
error_log:
location: /var/log/nginx/error.log
level: warn
worker_connections: 1024
http_enable: true
access_log_format:
- name: upstream_info
format: |-
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"'
access_log_location:
- name: upstream_info
location: /var/log/nginx/access.log
but the nginx.conf is getting the default values:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
I am running Ansible 4.1 and I have the 0.3.3 nginxinc.nginx_core collection
(cluster) joan@DESKTOP-OM8Q4NE:~/Abzu/cluster$ ansible --version
ansible [core 2.11.1]
config file = /home/joan/Abzu/cluster/ansible.cfg
configured module search path = ['/home/joan/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/joan/.local/share/virtualenvs/cluster-DtMsh1G5/lib/python3.8/site-packages/ansible
ansible collection location = /home/joan/.ansible/collections:/usr/share/ansible/collections
executable location = /home/joan/.local/share/virtualenvs/cluster-DtMsh1G5/bin/ansible
python version = 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0]
jinja version = 3.0.0
libyaml = True
Describe the bug
On a target host with SELinux state enforcing
, running the role with nginx_config_selinux: true
sets the target host SELinux state to permissive
To reproduce
Steps to reproduce the behavior:
enforcing
(used a CentOS 7 host as target), deploy NGINX Config role using nginx_config_selinux: true
( note: the role variable nginx_config_selinux_enforcing
was unchanged from the role default (true))getenforce
command. It returned Permissive
Expected behavior
Expected SELinux state to remain enforcing
Your environment:
Additional context
Excerpt from playbook output (-v):
TASK [external-roles/nginxinc.nginx-config : Set SELinux mode to permissive] ***********************
ok: [targethost] => changed=false
configfile: /etc/selinux/config
msg: SELinux state changed from 'enforcing' to 'permissive', Config SELinux state changed from 'enforcing' to 'permissive'
policy: targeted
reboot_required: false
state: permissive
...
...
TASK [external-roles/nginxinc.nginx-config : Set SELinux mode to enforcing] ************************
skipping: [targethost] => changed=false
skip_reason: Conditional result was False
When running this role in check mode with selinux enabled, this role will alway report a change.
With nginx_selinux_enforcing
set to true
, run the role, then run the role again with --check.
No changes identified when running ansible in check mode.
👋 Hello! I'd like to submit a feature request/discussion.
Today when provisioning one of my NGINX servers, it directed me to increase the server_names_hash_bucket_size to 64. This presumably happens when the individual servers have long names/domains.
I'm configuring my NGINX configs with this role, but I didn't find a value in the template for this setting.
Include the setting in this role.
Manual patching or provisioning of the config.
Error returned from Ansible on server restart:
I could potentially also help with implementing this feature.
Thanks for replying and especially for maintaining this project! 👏
I'm trying to setup a simple HTTP server on a Debian machine with the following config:
# my_role/meta/main.yml
---
allow_duplicates: no
dependencies:
- role: nginxinc.nginx
become: yes
- role: nginxinc.nginx_config
become: yes
vars:
nginx_config_debug_output: true
nginx_config_debug_tasks: true
nginx_config_cleanup: true
nginx_config_cleanup_files:
- /etc/nginx/conf.d/default.conf
nginx_config_main_template_enable: true
nginx_config_main_template:
user: pi
http_enable: true
http_settings:
gzip:
enable: true
access_log_format:
- name: main
format: |-
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
access_log_location:
- name: main
location: /var/log/nginx/access.log
keepalive_timeout: 65
nginx_config_http_template_enable: true
nginx_config_http_template:
# - template_file: http/default.conf.j2
# conf_file_name: default.v1.conf
# conf_file_location: /etc/nginx/conf.d/
- servers:
- server_name: localhost
listen:
- ip: localhost
port: 80
gzip:
enable: true
root: "{{ ui_pkg_dst }}"
index: index.html
try_files: $uri $uri/index.html $uri.html =404
locations:
- location: /
root: "{{ ui_pkg_dst }}"
index: index.html
try_files: $uri $uri/index.html $uri.html =404
But it seems like the config file on the remote host is always empty or contains just the comment:
TASK [Gathering Facts] *******************************************************************************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx : Check whether you are using a supported NGINX distribution] *******************************************************************************************************************************
ok: [dum-e] => {
"changed": false,
"msg": "Your OS, Debian is supported by NGINX Open Source"
}
TASK [nginxinc.nginx : Set up prerequisites] *********************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx/tasks/prerequisites/prerequisites.yml for dum-e
TASK [nginxinc.nginx : Install dependencies] *********************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx/tasks/prerequisites/install-dependencies.yml for dum-e
TASK [nginxinc.nginx : (Alpine Linux) Install dependencies] ******************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : (Debian/Ubuntu) Install dependencies] *****************************************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx : (Amazon Linux/CentOS/Oracle Linux/RHEL) Install dependencies] *****************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : (SLES) Install dependencies] **************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : (FreeBSD) Install dependencies using package(s)] ******************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : (FreeBSD) Install dependencies using port(s)] *********************************************************************************************************************************************
skipping: [dum-e] => (item=security/ca_root_nss)
TASK [nginxinc.nginx : Check if SELinux is enabled] **************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Configure SELinux] ************************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Set up signing keys] **********************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx/tasks/keys/setup-keys.yml for dum-e
TASK [nginxinc.nginx : (Alpine Linux) Set up NGINX signing key URL] **********************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : (Alpine Linux) Download NGINX signing key] ************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : (Debian/Red Hat/SLES OSs) Set up NGINX signing key URL] ***********************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx : (Debian/Ubuntu) Add NGINX signing key] ****************************************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx : (Amazon Linux/CentOS/Oracle Linux/RHEL/SLES) Add NGINX signing key] ***********************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Install NGINX Open Source] ****************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx/tasks/opensource/install-oss.yml for dum-e
TASK [nginxinc.nginx : Install NGINX from repository] ************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx/tasks/opensource/install-debian.yml for dum-e
TASK [nginxinc.nginx : (Debian/Ubuntu) Configure NGINX repository] ***********************************************************************************************************************************************
ok: [dum-e] => (item=deb [arch=amd64] https://nginx.org/packages/mainline/debian/ buster nginx)
ok: [dum-e] => (item=deb-src https://nginx.org/packages/mainline/debian/ buster nginx)
TASK [nginxinc.nginx : (Debian/Ubuntu) Install NGINX] ************************************************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx : Install NGINX from source] ****************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Install NGINX from package] ***************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Install NGINX in Unix systems] ************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Set up NGINX Plus license] ****************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Install NGINX Plus] ***********************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Install NGINX modules] ********************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Remove NGINX Plus license] ****************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Modify systemd parameters] ****************************************************************************************************************************************************************
skipping: [dum-e]
[WARNING]: flush_handlers task does not support when conditional
TASK [nginxinc.nginx : Debug NGINX output] ***********************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Configure logrotate for NGINX] ************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx : Install NGINX Amplify] ********************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx_config : Set up SELinux] ********************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx_config : Cleanup NGINX config] **************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx_config/tasks/config/cleanup-config.yml for dum-e
TASK [nginxinc.nginx_config : Find NGINX config files] ***********************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx_config : Remove NGINX config files] *********************************************************************************************************************************************************
changed: [dum-e] => (item=/etc/nginx/conf.d/default.conf)
TASK [nginxinc.nginx_config : Upload NGINX config] ***************************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx_config : Create NGINX config] ***************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx_config/tasks/config/template-config.yml for dum-e
TASK [nginxinc.nginx_config : Ensure HTML directory exists] ******************************************************************************************************************************************************
skipping: [dum-e] => (item={'key': 'default', 'value': {'template_file': 'www/index.html.j2', 'html_file_name': 'index.html', 'html_file_location': '/usr/share/nginx/html', 'web_server_name': 'Default'}})
TASK [nginxinc.nginx_config : Dynamically generate HTML files] ***************************************************************************************************************************************************
skipping: [dum-e] => (item={'key': 'default', 'value': {'template_file': 'www/index.html.j2', 'html_file_name': 'index.html', 'html_file_location': '/usr/share/nginx/html', 'web_server_name': 'Default'}})
TASK [nginxinc.nginx_config : Configure NGINX modules] ***********************************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx_config : Ensure NGINX main directory exists] ************************************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx_config : Dynamically generate NGINX main configuration file] ********************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx_config : Ensure NGINX HTTP directory exists] ************************************************************************************************************************************************
ok: [dum-e] => (item={'key': 'servers', 'value': [{'server_name': 'localhost', 'listen': [{'ip': 'localhost', 'port': 80}], 'gzip': {'enable': True}, 'root': '/home/pi/ui', 'index': 'index.html', 'try_files': '$uri $uri/index.html $uri.html =404', 'locations': [{'location': '/', 'root': '/home/pi/ui', 'index': 'index.html', 'try_files': '$uri $uri/index.html $uri.html =404'}]}]})
TASK [nginxinc.nginx_config : Ensure NGINX proxy cache directories exist] ****************************************************************************************************************************************
TASK [nginxinc.nginx_config : Dynamically generate NGINX HTTP config files] **************************************************************************************************************************************
changed: [dum-e] => (item={'key': 'servers', 'value': [{'server_name': 'localhost', 'listen': [{'ip': 'localhost', 'port': 80}], 'gzip': {'enable': True}, 'root': '/home/pi/ui', 'index': 'index.html', 'try_files': '$uri $uri/index.html $uri.html =404', 'locations': [{'location': '/', 'root': '/home/pi/ui', 'index': 'index.html', 'try_files': '$uri $uri/index.html $uri.html =404'}]}]})
TASK [nginxinc.nginx_config : Dynamically generate NGINX stub status config file] ********************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx_config : Dynamically generate NGINX API config file] ****************************************************************************************************************************************
skipping: [dum-e]
TASK [nginxinc.nginx_config : Ensure NGINX stream directory exists] **********************************************************************************************************************************************
skipping: [dum-e] => (item={'key': 'default', 'value': {'template_file': 'stream/default.conf.j2', 'conf_file_name': 'default.conf', 'conf_file_location': '/etc/nginx/conf.d/stream/', 'network_streams': {'default': {'listen': {'listen_localhost': {'ip': '0.0.0.0', 'port': 80, 'ssl': False, 'opts': []}}, 'ssl': {'cert': '/etc/ssl/certs/default.crt', 'key': '/etc/ssl/private/default.key', 'dhparam': '/etc/ssl/private/dh_param.pem', 'protocols': 'TLSv1 TLSv1.1 TLSv1.2', 'ciphers': 'HIGH:!aNULL:!MD5', 'prefer_server_ciphers': True, 'session_cache': 'none', 'session_timeout': '5m', 'disable_session_tickets': False, 'trusted_cert': '/etc/ssl/certs/root_CA_cert_plus_intermediates.crt', 'ecdh_curve': 'auto'}, 'include_files': [], 'proxy_pass': 'backend', 'proxy_timeout': '3s', 'proxy_connect_timeout': '1s', 'proxy_protocol': False, 'proxy_ssl': {'cert': '/etc/ssl/certs/proxy_default.crt', 'key': '/etc/ssl/private/proxy_default.key', 'trusted_cert': '/etc/ssl/certs/proxy_ca.crt', 'protocols': 'TLSv1 TLSv1.1 TLSv1.2', 'ciphers': 'HIGH:!aNULL:!MD5', 'verify': False, 'verify_depth': 1, 'session_reuse': True}, 'health_check_plus': False}}, 'upstreams': {'upstream1': {'name': 'backend', 'lb_method': 'least_conn', 'zone_name': 'backend', 'zone_size': '64k', 'sticky_cookie': False, 'servers': {'server1': {'address': 'localhost', 'port': 8080, 'weight': 1, 'health_check': 'max_fails=1 fail_timeout=10s'}}}}}})
TASK [nginxinc.nginx_config : Dynamically generate NGINX stream config files] ************************************************************************************************************************************
skipping: [dum-e] => (item={'key': 'default', 'value': {'template_file': 'stream/default.conf.j2', 'conf_file_name': 'default.conf', 'conf_file_location': '/etc/nginx/conf.d/stream/', 'network_streams': {'default': {'listen': {'listen_localhost': {'ip': '0.0.0.0', 'port': 80, 'ssl': False, 'opts': []}}, 'ssl': {'cert': '/etc/ssl/certs/default.crt', 'key': '/etc/ssl/private/default.key', 'dhparam': '/etc/ssl/private/dh_param.pem', 'protocols': 'TLSv1 TLSv1.1 TLSv1.2', 'ciphers': 'HIGH:!aNULL:!MD5', 'prefer_server_ciphers': True, 'session_cache': 'none', 'session_timeout': '5m', 'disable_session_tickets': False, 'trusted_cert': '/etc/ssl/certs/root_CA_cert_plus_intermediates.crt', 'ecdh_curve': 'auto'}, 'include_files': [], 'proxy_pass': 'backend', 'proxy_timeout': '3s', 'proxy_connect_timeout': '1s', 'proxy_protocol': False, 'proxy_ssl': {'cert': '/etc/ssl/certs/proxy_default.crt', 'key': '/etc/ssl/private/proxy_default.key', 'trusted_cert': '/etc/ssl/certs/proxy_ca.crt', 'protocols': 'TLSv1 TLSv1.1 TLSv1.2', 'ciphers': 'HIGH:!aNULL:!MD5', 'verify': False, 'verify_depth': 1, 'session_reuse': True}, 'health_check_plus': False}}, 'upstreams': {'upstream1': {'name': 'backend', 'lb_method': 'least_conn', 'zone_name': 'backend', 'zone_size': '64k', 'sticky_cookie': False, 'servers': {'server1': {'address': 'localhost', 'port': 8080, 'weight': 1, 'health_check': 'max_fails=1 fail_timeout=10s'}}}}}})
RUNNING HANDLER [nginxinc.nginx_config : (Handler - NGINX Config) Check NGINX] ***********************************************************************************************************************************
ok: [dum-e]
RUNNING HANDLER [nginxinc.nginx_config : (Handler - NGINX Config) Print NGINX error if syntax check fails] *******************************************************************************************************
skipping: [dum-e]
RUNNING HANDLER [nginxinc.nginx_config : (Handler - NGINX Config) Start/reload NGINX] ****************************************************************************************************************************
changed: [dum-e]
TASK [nginxinc.nginx_config : Debug output] **********************************************************************************************************************************************************************
included: /Users/rolandgroza/.ansible/roles/nginxinc.nginx_config/tasks/config/debug-output.yml for dum-e
TASK [nginxinc.nginx_config : Register NGINX config] *************************************************************************************************************************************************************
ok: [dum-e]
TASK [nginxinc.nginx_config : Print NGINX config] ****************************************************************************************************************************************************************
ok: [dum-e] => {
"config_full.stdout_lines": [
"# configuration file /etc/nginx/nginx.conf:",
"#",
"# Ansible managed",
"#",
"",
"",
"user pi;",
"",
"",
"",
"events {",
"}",
"",
"http {",
" include /etc/nginx/mime.types;",
" default_type application/octet-stream;",
" log_format main '$remote_addr - $remote_user [$time_local] \"$request\" '",
"'$status $body_bytes_sent \"$http_referer\" '",
"'\"$http_user_agent\" \"$http_x_forwarded_for\"';",
" access_log /var/log/nginx/access.log main;",
" keepalive_timeout 65;",
" gzip on;",
"",
" include /etc/nginx/conf.d/*.conf;",
"}",
"",
"",
"# configuration file /etc/nginx/mime.types:",
"",
"types {",
" text/html html htm shtml;",
" text/css css;",
" text/xml xml;",
" image/gif gif;",
" image/jpeg jpeg jpg;",
" application/javascript js;",
" application/atom+xml atom;",
" application/rss+xml rss;",
"",
" text/mathml mml;",
" text/plain txt;",
" text/vnd.sun.j2me.app-descriptor jad;",
" text/vnd.wap.wml wml;",
" text/x-component htc;",
"",
" image/png png;",
" image/tiff tif tiff;",
" image/vnd.wap.wbmp wbmp;",
" image/x-icon ico;",
" image/x-jng jng;",
" image/x-ms-bmp bmp;",
" image/svg+xml svg svgz;",
" image/webp webp;",
"",
" application/font-woff woff;",
" application/java-archive jar war ear;",
" application/json json;",
" application/mac-binhex40 hqx;",
" application/msword doc;",
" application/pdf pdf;",
" application/postscript ps eps ai;",
" application/rtf rtf;",
" application/vnd.apple.mpegurl m3u8;",
" application/vnd.ms-excel xls;",
" application/vnd.ms-fontobject eot;",
" application/vnd.ms-powerpoint ppt;",
" application/vnd.wap.wmlc wmlc;",
" application/vnd.google-earth.kml+xml kml;",
" application/vnd.google-earth.kmz kmz;",
" application/x-7z-compressed 7z;",
" application/x-cocoa cco;",
" application/x-java-archive-diff jardiff;",
" application/x-java-jnlp-file jnlp;",
" application/x-makeself run;",
" application/x-perl pl pm;",
" application/x-pilot prc pdb;",
" application/x-rar-compressed rar;",
" application/x-redhat-package-manager rpm;",
" application/x-sea sea;",
" application/x-shockwave-flash swf;",
" application/x-stuffit sit;",
" application/x-tcl tcl tk;",
" application/x-x509-ca-cert der pem crt;",
" application/x-xpinstall xpi;",
" application/xhtml+xml xhtml;",
" application/xspf+xml xspf;",
" application/zip zip;",
"",
" application/octet-stream bin exe dll;",
" application/octet-stream deb;",
" application/octet-stream dmg;",
" application/octet-stream iso img;",
" application/octet-stream msi msp msm;",
"",
" application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;",
" application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;",
" application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;",
"",
" audio/midi mid midi kar;",
" audio/mpeg mp3;",
" audio/ogg ogg;",
" audio/x-m4a m4a;",
" audio/x-realaudio ra;",
"",
" video/3gpp 3gpp 3gp;",
" video/mp2t ts;",
" video/mp4 mp4;",
" video/mpeg mpeg mpg;",
" video/quicktime mov;",
" video/webm webm;",
" video/x-flv flv;",
" video/x-m4v m4v;",
" video/x-mng mng;",
" video/x-ms-asf asx asf;",
" video/x-ms-wmv wmv;",
" video/x-msvideo avi;",
"}",
"",
"# configuration file /etc/nginx/conf.d/default.conf:",
"#",
"# Ansible managed",
"#"
]
}
Steps to reproduce the behavior:
/etc/nginx/conf.d/default.conf
contentsI'd expect the config file on the remote host to be generated with the config I've setup.
---
roles:
# https://github.com/nginxinc/ansible-role-nginx
- src: nginxinc.nginx
version: 0.19.1
# https://github.com/nginxinc/ansible-role-nginx-config
- src: nginxinc.nginx_config
version: 0.3.3
❯ ansible --version
ansible 2.10.2
config file = /Users/rolandgroza/Work/jigs/ansible.cfg
configured module search path = ['/Users/rolandgroza/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /Users/rolandgroza/.pyenv/versions/3.8.6/envs/python-3.8/lib/python3.8/site-packages/ansible
executable location = /Users/rolandgroza/.pyenv/versions/python-3.8/bin/ansible
python version = 3.8.6 (default, Nov 1 2020, 20:18:23) [Clang 11.0.3 (clang-1103.0.32.62)]
Add any other context about the problem here.
While running the molecule tests, the installation of NGINX Plus is failing.
Steps to reproduce the behavior:
main
molecule test --all
All tests passing
main
, commit 797232e0dbef01c0ce21ea3bd5ba48d26094df5e
I found this while testing my contribution. As it is happening on main
too, I don't see this related to my changes. If you think this is an edge case related to my own setup, please don't feel compelled to process this.
A clear and concise description of what the bug is.
there is a typo in line 7 of templates/http/api.conf.j2, in a result, the format can never been appended to the access_log line
the value: (status_rest_api_log
)
nginx_config_status_rest_api_log['format']
should be (rest_api_access_log
)
nginx_config_rest_api_access_log['format']
this is the line:
access_log{{ ' off' if not nginx_config_rest_api_access_log }}{{ (' ' + nginx_config_rest_api_access_log['path']) if nginx_config_rest_api_access_log['path'] is defined }}{{ (' ' + nginx_config_rest_api_access_log['format']) if nginx_config_status_rest_api_log['format'] is defined }};
besides, it is "name
" vs "format
" in the defaults/main/template.yml , you may also want to make it consistent. (as well as location
vs path
)
nginx_config_rest_api_access_log: # Optional -- Set to 'false' and remove/comment nested variables to disable access log
location: /var/log/nginx/api_access.log # Required
name: main # Required
Steps to reproduce the behavior:
A clear and concise description of what you expected to happen.
Add any other context about the problem here.
Currently, the conf role does not have configuration support for the directives in the real_ip module.
Add support for the real_ip directives at a minimum in the http
and server
NGINX contexts.
This is my current workaround, which is of course brittle:
tasks:
- name: Add XFF header settings to http block
ansible.builtin.blockinfile:
path: /etc/nginx/nginx.conf
insertbefore: '^\s*include\s\/etc\/nginx\/conf\.d\/\*.conf;'
block: |
real_ip_header X-Forwarded-For;
set_real_ip_from 0.0.0.0/0;
real_ip_recursive on;
- name: Add XFF header settings to server block
ansible.builtin.lineinfile:
path: /etc/nginx/conf.d/default.conf
regexp: '^\s*listen.*80\sdefault_server;\n\s*real_ip_header'
insertafter: '^\s*listen.*80\sdefault_server;'
line: 'real_ip_header X-Forwarded-For;'
- name: Restart NGINX
service:
name: nginx
state: restarted
enabled: true
The deployment fails due to
The error was: ansible.errors.AnsibleUndefinedVariable: the inline if-expression on line 71 in 'http/ssl.j2' evaluated to false and no else section was defined.
Steps to reproduce the behavior:
- hosts: all
collections:
- nginxinc.nginx_core
tasks:
- name: Configure NGINX
include_role:
name: nginx_config
vars:
nginx_config_http_template_enable: true
TASK [nginxinc.nginx_core.nginx_config : Dynamically generate NGINX HTTP config files] ********************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.errors.AnsibleUndefinedVariable: the inline if-expression on line 71 in 'http/ssl.j2' evaluated to false and no else section was defined.
failed: [gimci-vm15] (item={'template_file': 'http/default.conf.j2', 'deployment_location': '/etc/nginx/conf.d/default.conf', 'config': {'upstreams': [{'name': 'backend', 'servers': [{'address': 'localhost', 'weight': 1, 'max_conns': 0, 'max_fails': 1, 'fail_timeout': '10s', 'backup': False, 'down': False, 'resolve': False, 'service': 'http', 'route': 'a', 'slow_start': '0s', 'drain': False}], 'zone': {'name': 'backend_mem_zone', 'size': '64k'}, 'state': '/var/lib/nginx/state/servers.conf', 'hash': {'key': 'key', 'consistent': False}, 'ip_hash': False, 'least_conn': False, 'least_time': {'response': 'last_byte', 'inflight': False}, 'random': {'two': True, 'method': 'least_time=last_byte'}, 'queue': {'number': 10, 'timeout': '60s'}, 'keepalive': 32, 'keepalive_requests': 100, 'keepalive_time': '1h', 'keepalive_timeout': '60s', 'ntlm': False, 'resolver': {'address': [], 'valid': '30s', 'ipv6': False, 'status_zone': 'backend_mem_zone'}, 'resolver_timeout': '30s', 'sticky_cookie': {'name': 'cookie', 'expires': '1d', 'domain': 'example.com', 'httponly': False, 'samesite': 'none', 'secure': True, 'path': 'path'}, 'sticky_route': [], 'sticky_learn': {'create': [], 'lookup': [], 'zone': {'name': 'client_sessions', 'size': '1m'}, 'timeout': '10m', 'header': False, 'sync': False}}], 'core': {'absolute_redirect': True, 'aio': {'threads': True}, 'aio_write': False, 'alias': 'path', 'auth_delay': '0s', 'chunked_transfer_encoding': True, 'client_body_buffer_size': '8k', 'client_body_in_file_only': False, 'client_body_in_single_buffer': False, 'client_body_temp_path': {'path': '/var/cache/nginx', 'level': 2}, 'client_body_timeout': '60s', 'client_header_buffer_size': '1k', 'client_header_timeout': '60s', 'client_max_body_size': '1m', 'connection_pool_size': 256, 'default_type': 'text/plain', 'directio': False, 'directio_alignment': 512, 'disable_symlinks': {'check': 'on', 'from': '$document_root'}, 'error_page': [{'code': [404], 'response': 404, 'uri': '/404.html'}], 'etag': True, 'if_modified_since': 'exact', 'ignore_invalid_headers': True, 'include': 'path', 'internal': False, 'keepalive_disable': 'msie6', 'keepalive_requests': 1000, 'keepalive_time': '1h', 'keepalive_timeout': {'timeout': '75s', 'header_timeout': '75s'}, 'large_client_header_buffers': {'number': 4, 'size': '8k'}, 'limit_except': {'method': 'GET', 'directive': ['allow all']}, 'limit_rate': 0, 'limit_rate_after': 0, 'lingering_close': True, 'lingering_time': '30s', 'lingering_timeout': '5s', 'listen': [{'address': '0.0.0.0', 'port': 80, 'default_server': True, 'ssl': False, 'http2': False, 'spdy': False, 'proxy_protocol': False, 'fastopen': 12, 'backlog': 511, 'rcvbuf': 512, 'sndbuf': 512, 'deffered': False, 'bind': False, 'ipv6only': False, 'reuseport': False, 'so_keepalive': {'keepidle': '30m', 'keepintvl': 5, 'keepcnt': 10}}], 'log_not_found': True, 'log_subrequest': False, 'max_ranges': 0, 'merge_slashes': True, 'msie_padding': True, 'msie_refresh': False, 'open_file_cache': {'max': 10, 'inactive': '60s'}, 'open_file_cache_errors': False, 'open_file_cache_min_uses': 1, 'open_file_cache_valid': '60s', 'output_buffers': {'number': 2, 'size': '32k'}, 'port_in_redirect': True, 'postpone_output': 1460, 'read_ahead': 0, 'recursive_error_pages': False, 'request_pool_size': '4k', 'reset_timedout_connection': False, 'resolver': {'address': '127.0.0.1', 'valid': '60s', 'ipv6': False, 'status_zone': 'zone'}, 'resolver_timeout': '30s', 'root': 'html', 'index': 'path', 'satisfy': 'all', 'send_lowat': 0, 'send_timeout': '60s', 'sendfile': False, 'sendfile_max_chunk': 0, 'server_name': '', 'server_name_in_redirect': False, 'server_names_hash_bucket_size': 32, 'server_names_hash_max_size': 512, 'server_tokens': True, 'subrequest_output_buffer_size': '4k', 'tcp_nodelay': True, 'tcp_nopush': False, 'try_files': {'files': '$uri', 'uri': '/uri', 'code': 'code'}, 'types': [{'mime': 'text/html', 'extensions': 'html'}], 'types_hash_bucket_size': 64, 'types_hash_max_size': 1024, 'underscores_in_headers': False, 'variables_hash_bucket_size': 64, 'variables_hash_max_size': 1024}, 'ssl': {'buffer_size': '16k', 'certificate': '/path/to/file', 'certificate_key': '/path/to/file', 'ciphers': 'HIGH', 'client_certificate': '/path/to/file', 'conf_command': 'command', 'crl': '/path/to/file', 'dhparam': '/path/to/file', 'early_data': False, 'ecdh_curve': 'auto', 'ocsp': False, 'ocsp_cache': {'name': 'cache', 'size': '16k'}, 'ocsp_responder': '<url>', 'password_file': '/path/to/file', 'prefer_server_ciphers': False, 'protocols': 'TLSv1', 'reject_handshake': False, 'session_cache': {'builtin': {'enable': False, 'size': '16k'}}, 'session_ticket_key': '/path/to/file', 'session_tickets': True, 'session_timeout': '5m', 'stapling': False, 'stapling_file': '/path/to/file', 'stapling_responder': '<url>', 'stapling_verify': False, 'trusted_certificate': '/path/to/file', 'verify_client': False, 'verify_depth': 1}, 'app_protect_waf': {'physical_memory_util_thresholds': {'high': 100, 'low': 100}, 'cpu_thresholds': {'high': 100, 'low': 100}, 'failure_mode_action': 'pass', 'cookie_seed': 'encryptionseed', 'compressed_requests_action': 'drop', 'reconnect_period_seconds': 5, 'request_buffer_overflow_action': 'pass', 'user_defined_signatures': '/path/to/file', 'enable': False, 'policy_file': '/path/to/file', 'security_log_enable': False, 'security_log': [{'path': '/path/to/file', 'dest': 'dest'}]}, 'app_protect_dos': {'enable': True, 'policy_file': '/etc/app_protect/conf/BADOSDefaultPolicy.json', 'name': 'samplename', 'monitor': {'uri': 'http://10.1.1.1:5000/monitor', 'protocol': 'http2', 'timeout': 10}, 'security_log_enable': True, 'security_log': {'path': '/etc/app_protect_dos/log-default.json', 'dest': 'syslog:server=10.1.1.1:514'}, 'liveness': {'enable': True, 'uri': 'example.com', 'port': 80}, 'readiness': {'enable': True, 'uri': 'example.com', 'port': 80}}, 'proxy': {'bind': {'address': '0.0.0.0', 'transparent': False}, 'buffer_size': '4k', 'buffering': True, 'buffers': {'number': 8, 'size': '4k'}, 'busy_buffers_size': '8k', 'cache': False, 'cache_background_update': False, 'cache_bypass': '$cookie_seed', 'cache_convert_head': True, 'cache_key': '$scheme$proxy_host$request_uri', 'cache_lock': False, 'cache_lock_age': '5s', 'cache_lock_timeout': '5s', 'cache_max_range_offset': 1, 'cache_methods': 'GET', 'cache_min_uses': 1, 'cache_path': [{'path': '/var/cache/nginx/proxy/backend', 'levels': '1:1', 'use_temp_path': False, 'keys_zone': {'name': 'backend_proxy_cache', 'size': '10m'}, 'inactive': '10m', 'max_size': '2g', 'min_free': '1g', 'manager_files': 100, 'manager_sleep': '500ms', 'manager_threshold': '200ms', 'loader_files': 100, 'loader_sleep': '50ms', 'loader_threshold': '200ms', 'purger': False, 'purger_files': 10, 'purger_sleep': '50ms', 'purger_threshold': '50ms'}], 'cache_purge': 'sample', 'cache_revalidate': False, 'cache_use_stale': False, 'cache_valid': [{'code': 200, 'time': '10m'}, '2m'], 'connect_timeout': '60s', 'cookie_domain': [{'domain': 'localhost', 'replacement': 'example.org'}], 'cookie_flags': {'cookie': 'one', 'flag': ['httponly']}, 'cookie_path': [{'path': '$uri', 'replacement': '$someuri'}], 'force_ranges': False, 'headers_hash_bucket_size': 64, 'headers_hash_max_size': 512, 'hide_header': 'Date', 'http_version': 1.1, 'ignore_client_abort': False, 'ignore_headers': 'X-Accel-Redirect', 'intercept_errors': False, 'limit_rate': 0, 'max_temp_file_size': '1024m', 'method': 'GET', 'next_upstream': False, 'next_upstream_timeout': 0, 'next_upstream_tries': 0, 'no_cache': '$cookie_nocache', 'pass': 'http://127.0.0.1', 'pass_header': 'Date', 'pass_request_body': False, 'pass_request_headers': True, 'read_timeout': '60s', 'redirect': {'original': 'http://upstream:port/two/', 'replacement': '/one/'}, 'request_buffering': False, 'send_lowat': 0, 'send_timeout': '60s', 'set_body': 'body', 'set_header': {'field': 'Host', 'value': '$proxy_host'}, 'socket_keepalive': False, 'ssl_certificate': '/path/to/file', 'ssl_certificate_key': '/path/to/file', 'ssl_ciphers': 'DEFAULT', 'ssl_conf_command': 'command', 'ssl_crl': '/path/to/file', 'ssl_name': '$proxy_host', 'ssl_password_file': '/path/to/file', 'ssl_protocols': 'TLSv1', 'ssl_server_name': False, 'ssl_session_reuse': True, 'ssl_trusted_certificate': '/path/to/file', 'ssl_verify': False, 'ssl_verify_depth': 1, 'store': False, 'store_access': {'user': 'rw', 'group': 'rw', 'all': 'r'}, 'temp_file_write_size': '8k', 'temp_path': {'path': '/var/cache/nginx/proxy/temp', 'level': 2}}, 'grpc': {'bind': {'address': '$remote_addr', 'transparent': True}, 'buffer_size': '4k', 'connect_timeout': '60s', 'hide_header': [], 'ignore_headers': [], 'intercept_errors': False, 'next_upstream': [], 'next_upstream_timeout': 0, 'next_upstream_tries': 0, 'pass': 'uri', 'pass_header': [], 'read_timeout': '60s', 'send_timeout': '60s', 'set_header': [{'field': 'Accept-Encoding', 'value': '""'}], 'socket_keepalive': False, 'ssl_certificate': '/path/to/file', 'ssl_certificate_key': '/path/to/file', 'ssl_ciphers': 'DEFAULT', 'ssl_conf_command': 'command', 'ssl_crl': '/path/to/file', 'ssl_name': 'serverName', 'ssl_password_file': '/path/to/file', 'ssl_protocols': [], 'ssl_server_name': False, 'ssl_session_reuse': True, 'ssl_trusted_certificate': '/path/to/file', 'ssl_verify': False, 'ssl_verify_depth': 1}, 'access': {'allow': 'localhost', 'deny': '192.168.1.100'}, 'auth_basic': {'realm': False, 'user_file': '/path/to/file'}, 'auth_request': {'uri': False, 'set': {'variable': '$temp', 'value': 'auth'}}, 'auth_jwt': {'enable': {'realm': 'realm', 'token': '$cookie_auth_token'}, 'claim_set': [{'variable': '$email', 'name': ['info']}], 'header_set': [{'variable': '$job', 'name': 'info'}], 'key_file': '/path/to/file', 'key_request': '/path/to/file', 'leeway': '0s', 'type': 'signed', 'require': '$valid_jwt_iss'}, 'api': {'enable': {'write': True}, 'status_zone': 'one'}, 'stub_status': True, 'autoindex': {'enable': False, 'exact_size': True, 'format': 'html', 'localtime': False}, 'gzip': {'enable': True, 'buffers': {'number': 32, 'size': '4k'}, 'comp_level': 1, 'disable': [], 'http_version': 1.1, 'min_length': 20, 'proxied': [], 'types': [], 'vary': False}, 'headers': {'add_headers': [{'name': 'Strict-Transport-Security', 'value': '"max-age=15768000; includeSubDomains"', 'always': False}], 'add_trailers': [{'name': 'Strict-Transport-Security', 'value': '"max-age=15768000; includeSubDomains"', 'always': False}], 'expires': {'modified': True, 'time': '12h'}}, 'health_check': {'health_checks': [{'interval': '5s', 'jitter': 0, 'fails': 1, 'passes': 1, 'uri': '/', 'mandatory': False, 'persistent': False, 'match': 'match', 'port': 80, 'grpc_service': 'service', 'grpc_status': 12}], 'match': [{'name': 'name', 'conditions': []}]}, 'keyval': {'keyvals': [{'key': 'key', 'variable': '$var', 'zone': 'one'}], 'zones': [{'name': 'one', 'size': '32k', 'state': '/var/lib/nginx/state/one.keyval', 'timeout': '60m', 'type': 'string', 'sync': False}]}, 'limit_req': {'limit_reqs': [{'zone': 'one', 'burst': 5, 'delay': False}], 'dry_run': False, 'log_level': 'error', 'status': 503, 'zones': [{'key': '$binary_remote_addr', 'name': 'one', 'size': '1m', 'rate': '10r/s', 'sync': False}]}, 'log': {'format': [{'name': 'main', 'escape': 'default', 'format': '\'$remote_addr - $remote_user [$time_local] "$request" \'\n\'$status $body_bytes_sent "$http_referer" \'\n\'"$http_user_agent" "$http_x_forwarded_for"\'\n'}], 'access': [{'path': '/var/log/nginx/access.log', 'format': 'main', 'buffer': '1m', 'gzip': 5, 'flush': '10h', 'if': '$loggable'}], 'error': {'file': '/var/log/nginx/error.log', 'level': 'notice'}, 'open_log_file_cache': {'max': 1000, 'inactive': '20s', 'min_uses': 2, 'valid': '1m'}}, 'rewrite': {'return': {'code': 200, 'text': 'text', 'url': 'https://example.com'}, 'rewrites': [{'regex': '(.*).html(.*)', 'replacement': '$1$2', 'flag': 'last'}], 'log': False, 'set': [{'variable': '$var', 'value': 'var'}], 'uninitialized_variable_warn': True}, 'sub_filter': {'sub_filters': [{'string': 'server_hostname', 'replacement': '$hostname'}], 'last_modified': False, 'once': True, 'types': 'text/html'}, 'custom_directives': ['fastcgi_split_path_info ^(.+\\.php)(/.+)$;', 'fastcgi_pass unix:/run/php/php7.2-fpm.sock;'], 'servers': [{'core': None, 'proxy': None, 'locations': [{'location': '/', 'proxy': None}]}, {'core': None, 'ssl': None, 'locations': [{'location': '/backend', 'core': None}]}]}}) => {"ansible_loop_var": "item", "changed": false, "item": {"config": {"access": {"allow": "localhost", "deny": "192.168.1.100"}, "api": {"enable": {"write": true}, "status_zone": "one"}, "app_protect_dos": {"enable": true, "liveness": {"enable": true, "port": 80, "uri": "example.com"}, "monitor": {"protocol": "http2", "timeout": 10, "uri": "http://10.1.1.1:5000/monitor"}, "name": "samplename", "policy_file": "/etc/app_protect/conf/BADOSDefaultPolicy.json", "readiness": {"enable": true, "port": 80, "uri": "example.com"}, "security_log": {"dest": "syslog:server=10.1.1.1:514", "path": "/etc/app_protect_dos/log-default.json"}, "security_log_enable": true}, "app_protect_waf": {"compressed_requests_action": "drop", "cookie_seed": "encryptionseed", "cpu_thresholds": {"high": 100, "low": 100}, "enable": false, "failure_mode_action": "pass", "physical_memory_util_thresholds": {"high": 100, "low": 100}, "policy_file": "/path/to/file", "reconnect_period_seconds": 5, "request_buffer_overflow_action": "pass", "security_log": [{"dest": "dest", "path": "/path/to/file"}], "security_log_enable": false, "user_defined_signatures": "/path/to/file"}, "auth_basic": {"realm": false, "user_file": "/path/to/file"}, "auth_jwt": {"claim_set": [{"name": ["info"], "variable": "$email"}], "enable": {"realm": "realm", "token": "$cookie_auth_token"}, "header_set": [{"name": "info", "variable": "$job"}], "key_file": "/path/to/file", "key_request": "/path/to/file", "leeway": "0s", "require": "$valid_jwt_iss", "type": "signed"}, "auth_request": {"set": {"value": "auth", "variable": "$temp"}, "uri": false}, "autoindex": {"enable": false, "exact_size": true, "format": "html", "localtime": false}, "core": {"absolute_redirect": true, "aio": {"threads": true}, "aio_write": false, "alias": "path", "auth_delay": "0s", "chunked_transfer_encoding": true, "client_body_buffer_size": "8k", "client_body_in_file_only": false, "client_body_in_single_buffer": false, "client_body_temp_path": {"level": 2, "path": "/var/cache/nginx"}, "client_body_timeout": "60s", "client_header_buffer_size": "1k", "client_header_timeout": "60s", "client_max_body_size": "1m", "connection_pool_size": 256, "default_type": "text/plain", "directio": false, "directio_alignment": 512, "disable_symlinks": {"check": "on", "from": "$document_root"}, "error_page": [{"code": [404], "response": 404, "uri": "/404.html"}], "etag": true, "if_modified_since": "exact", "ignore_invalid_headers": true, "include": "path", "index": "path", "internal": false, "keepalive_disable": "msie6", "keepalive_requests": 1000, "keepalive_time": "1h", "keepalive_timeout": {"header_timeout": "75s", "timeout": "75s"}, "large_client_header_buffers": {"number": 4, "size": "8k"}, "limit_except": {"directive": ["allow all"], "method": "GET"}, "limit_rate": 0, "limit_rate_after": 0, "lingering_close": true, "lingering_time": "30s", "lingering_timeout": "5s", "listen": [{"address": "0.0.0.0", "backlog": 511, "bind": false, "default_server": true, "deffered": false, "fastopen": 12, "http2": false, "ipv6only": false, "port": 80, "proxy_protocol": false, "rcvbuf": 512, "reuseport": false, "sndbuf": 512, "so_keepalive": {"keepcnt": 10, "keepidle": "30m", "keepintvl": 5}, "spdy": false, "ssl": false}], "log_not_found": true, "log_subrequest": false, "max_ranges": 0, "merge_slashes": true, "msie_padding": true, "msie_refresh": false, "open_file_cache": {"inactive": "60s", "max": 10}, "open_file_cache_errors": false, "open_file_cache_min_uses": 1, "open_file_cache_valid": "60s", "output_buffers": {"number": 2, "size": "32k"}, "port_in_redirect": true, "postpone_output": 1460, "read_ahead": 0, "recursive_error_pages": false, "request_pool_size": "4k", "reset_timedout_connection": false, "resolver": {"address": "127.0.0.1", "ipv6": false, "status_zone": "zone", "valid": "60s"}, "resolver_timeout": "30s", "root": "html", "satisfy": "all", "send_lowat": 0, "send_timeout": "60s", "sendfile": false, "sendfile_max_chunk": 0, "server_name": "", "server_name_in_redirect": false, "server_names_hash_bucket_size": 32, "server_names_hash_max_size": 512, "server_tokens": true, "subrequest_output_buffer_size": "4k", "tcp_nodelay": true, "tcp_nopush": false, "try_files": {"code": "code", "files": "$uri", "uri": "/uri"}, "types": [{"extensions": "html", "mime": "text/html"}], "types_hash_bucket_size": 64, "types_hash_max_size": 1024, "underscores_in_headers": false, "variables_hash_bucket_size": 64, "variables_hash_max_size": 1024}, "custom_directives": ["fastcgi_split_path_info ^(.+\\.php)(/.+)$;", "fastcgi_pass unix:/run/php/php7.2-fpm.sock;"], "grpc": {"bind": {"address": "$remote_addr", "transparent": true}, "buffer_size": "4k", "connect_timeout": "60s", "hide_header": [], "ignore_headers": [], "intercept_errors": false, "next_upstream": [], "next_upstream_timeout": 0, "next_upstream_tries": 0, "pass": "uri", "pass_header": [], "read_timeout": "60s", "send_timeout": "60s", "set_header": [{"field": "Accept-Encoding", "value": "\"\""}], "socket_keepalive": false, "ssl_certificate": "/path/to/file", "ssl_certificate_key": "/path/to/file", "ssl_ciphers": "DEFAULT", "ssl_conf_command": "command", "ssl_crl": "/path/to/file", "ssl_name": "serverName", "ssl_password_file": "/path/to/file", "ssl_protocols": [], "ssl_server_name": false, "ssl_session_reuse": true, "ssl_trusted_certificate": "/path/to/file", "ssl_verify": false, "ssl_verify_depth": 1}, "gzip": {"buffers": {"number": 32, "size": "4k"}, "comp_level": 1, "disable": [], "enable": true, "http_version": 1.1, "min_length": 20, "proxied": [], "types": [], "vary": false}, "headers": {"add_headers": [{"always": false, "name": "Strict-Transport-Security", "value": "\"max-age=15768000; includeSubDomains\""}], "add_trailers": [{"always": false, "name": "Strict-Transport-Security", "value": "\"max-age=15768000; includeSubDomains\""}], "expires": {"modified": true, "time": "12h"}}, "health_check": {"health_checks": [{"fails": 1, "grpc_service": "service", "grpc_status": 12, "interval": "5s", "jitter": 0, "mandatory": false, "match": "match", "passes": 1, "persistent": false, "port": 80, "uri": "/"}], "match": [{"conditions": [], "name": "name"}]}, "keyval": {"keyvals": [{"key": "key", "variable": "$var", "zone": "one"}], "zones": [{"name": "one", "size": "32k", "state": "/var/lib/nginx/state/one.keyval", "sync": false, "timeout": "60m", "type": "string"}]}, "limit_req": {"dry_run": false, "limit_reqs": [{"burst": 5, "delay": false, "zone": "one"}], "log_level": "error", "status": 503, "zones": [{"key": "$binary_remote_addr", "name": "one", "rate": "10r/s", "size": "1m", "sync": false}]}, "log": {"access": [{"buffer": "1m", "flush": "10h", "format": "main", "gzip": 5, "if": "$loggable", "path": "/var/log/nginx/access.log"}], "error": {"file": "/var/log/nginx/error.log", "level": "notice"}, "format": [{"escape": "default", "format": "'$remote_addr - $remote_user [$time_local] \"$request\" '\n'$status $body_bytes_sent \"$http_referer\" '\n'\"$http_user_agent\" \"$http_x_forwarded_for\"'\n", "name": "main"}], "open_log_file_cache": {"inactive": "20s", "max": 1000, "min_uses": 2, "valid": "1m"}}, "proxy": {"bind": {"address": "0.0.0.0", "transparent": false}, "buffer_size": "4k", "buffering": true, "buffers": {"number": 8, "size": "4k"}, "busy_buffers_size": "8k", "cache": false, "cache_background_update": false, "cache_bypass": "$cookie_seed", "cache_convert_head": true, "cache_key": "$scheme$proxy_host$request_uri", "cache_lock": false, "cache_lock_age": "5s", "cache_lock_timeout": "5s", "cache_max_range_offset": 1, "cache_methods": "GET", "cache_min_uses": 1, "cache_path": [{"inactive": "10m", "keys_zone": {"name": "backend_proxy_cache", "size": "10m"}, "levels": "1:1", "loader_files": 100, "loader_sleep": "50ms", "loader_threshold": "200ms", "manager_files": 100, "manager_sleep": "500ms", "manager_threshold": "200ms", "max_size": "2g", "min_free": "1g", "path": "/var/cache/nginx/proxy/backend", "purger": false, "purger_files": 10, "purger_sleep": "50ms", "purger_threshold": "50ms", "use_temp_path": false}], "cache_purge": "sample", "cache_revalidate": false, "cache_use_stale": false, "cache_valid": [{"code": 200, "time": "10m"}, "2m"], "connect_timeout": "60s", "cookie_domain": [{"domain": "localhost", "replacement": "example.org"}], "cookie_flags": {"cookie": "one", "flag": ["httponly"]}, "cookie_path": [{"path": "$uri", "replacement": "$someuri"}], "force_ranges": false, "headers_hash_bucket_size": 64, "headers_hash_max_size": 512, "hide_header": "Date", "http_version": 1.1, "ignore_client_abort": false, "ignore_headers": "X-Accel-Redirect", "intercept_errors": false, "limit_rate": 0, "max_temp_file_size": "1024m", "method": "GET", "next_upstream": false, "next_upstream_timeout": 0, "next_upstream_tries": 0, "no_cache": "$cookie_nocache", "pass": "http://127.0.0.1", "pass_header": "Date", "pass_request_body": false, "pass_request_headers": true, "read_timeout": "60s", "redirect": {"original": "http://upstream:port/two/", "replacement": "/one/"}, "request_buffering": false, "send_lowat": 0, "send_timeout": "60s", "set_body": "body", "set_header": {"field": "Host", "value": "$proxy_host"}, "socket_keepalive": false, "ssl_certificate": "/path/to/file", "ssl_certificate_key": "/path/to/file", "ssl_ciphers": "DEFAULT", "ssl_conf_command": "command", "ssl_crl": "/path/to/file", "ssl_name": "$proxy_host", "ssl_password_file": "/path/to/file", "ssl_protocols": "TLSv1", "ssl_server_name": false, "ssl_session_reuse": true, "ssl_trusted_certificate": "/path/to/file", "ssl_verify": false, "ssl_verify_depth": 1, "store": false, "store_access": {"all": "r", "group": "rw", "user": "rw"}, "temp_file_write_size": "8k", "temp_path": {"level": 2, "path": "/var/cache/nginx/proxy/temp"}}, "rewrite": {"log": false, "return": {"code": 200, "text": "text", "url": "https://example.com"}, "rewrites": [{"flag": "last", "regex": "(.*).html(.*)", "replacement": "$1$2"}], "set": [{"value": "var", "variable": "$var"}], "uninitialized_variable_warn": true}, "servers": [{"core": null, "locations": [{"location": "/", "proxy": null}], "proxy": null}, {"core": null, "locations": [{"core": null, "location": "/backend"}], "ssl": null}], "ssl": {"buffer_size": "16k", "certificate": "/path/to/file", "certificate_key": "/path/to/file", "ciphers": "HIGH", "client_certificate": "/path/to/file", "conf_command": "command", "crl": "/path/to/file", "dhparam": "/path/to/file", "early_data": false, "ecdh_curve": "auto", "ocsp": false, "ocsp_cache": {"name": "cache", "size": "16k"}, "ocsp_responder": "<url>", "password_file": "/path/to/file", "prefer_server_ciphers": false, "protocols": "TLSv1", "reject_handshake": false, "session_cache": {"builtin": {"enable": false, "size": "16k"}}, "session_ticket_key": "/path/to/file", "session_tickets": true, "session_timeout": "5m", "stapling": false, "stapling_file": "/path/to/file", "stapling_responder": "<url>", "stapling_verify": false, "trusted_certificate": "/path/to/file", "verify_client": false, "verify_depth": 1}, "stub_status": true, "sub_filter": {"last_modified": false, "once": true, "sub_filters": [{"replacement": "$hostname", "string": "server_hostname"}], "types": "text/html"}, "upstreams": [{"hash": {"consistent": false, "key": "key"}, "ip_hash": false, "keepalive": 32, "keepalive_requests": 100, "keepalive_time": "1h", "keepalive_timeout": "60s", "least_conn": false, "least_time": {"inflight": false, "response": "last_byte"}, "name": "backend", "ntlm": false, "queue": {"number": 10, "timeout": "60s"}, "random": {"method": "least_time=last_byte", "two": true}, "resolver": {"address": [], "ipv6": false, "status_zone": "backend_mem_zone", "valid": "30s"}, "resolver_timeout": "30s", "servers": [{"address": "localhost", "backup": false, "down": false, "drain": false, "fail_timeout": "10s", "max_conns": 0, "max_fails": 1, "resolve": false, "route": "a", "service": "http", "slow_start": "0s", "weight": 1}], "state": "/var/lib/nginx/state/servers.conf", "sticky_cookie": {"domain": "example.com", "expires": "1d", "httponly": false, "name": "cookie", "path": "path", "samesite": "none", "secure": true}, "sticky_learn": {"create": [], "header": false, "lookup": [], "sync": false, "timeout": "10m", "zone": {"name": "client_sessions", "size": "1m"}}, "sticky_route": [], "zone": {"name": "backend_mem_zone", "size": "64k"}}]}, "deployment_location": "/etc/nginx/conf.d/default.conf", "template_file": "http/default.conf.j2"}, "msg": "AnsibleUndefinedVariable: the inline if-expression on line 71 in 'http/ssl.j2' evaluated to false and no else section was defined."}
Should not fail
A clear and concise description of what the bug is.
Deploy template fails with no test named 'boolean'
TASK [nginxinc.nginx_core.nginx_config : Dynamically generate NGINX HTTP config files] ******************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: jinja2.exceptions.TemplateAssertionError: no test named 'boolean'
failed: [host.fqdn] (item={'template_file': 'http/default.conf.j2', 'deployment_location': '/etc/nginx/conf.d/default.conf', 'config': {'upstreams': [{'name': 'upstr', 'least_conn': True, 'servers': [{'address': '0.0.0.0:8081'}, {'address': '0.0.0.0:8082'}]}], 'servers': [{'core': {'listen': [{'port': 80}], 'server_name': 'localhost'}, 'log': {'access': [{'path': '/var/log/nginx/access.log', 'format': 'main'}]}, 'locations': [{'location': '/', 'proxy': {'pass': 'http://upstr/', 'set_header': {'field': 'Host', 'value': '$host'}}}]}, {'core': {'listen': [{'port': 8081}], 'server_name': 'localhost'}, 'log': {'access': [{'path': '/var/log/nginx/access.log', 'format': 'main'}]}, 'locations': [{'location': '/', 'core': {'root': '/usr/share/nginx/html', 'index': 'server_one.html'}}], 'sub_filter': {'sub_filters': [{'string': 'server_hostname', 'replacement': '$hostname'}, {'string': 'server_address', 'replacement': '$server_addr:$server_port'}, {'string': 'server_url', 'replacement': '$request_uri'}, {'string': 'remote_addr', 'replacement': '$remote_addr:$remote_port'}, {'string': 'server_date', 'replacement': '$time_local'}, {'string': 'client_browser', 'replacement': '$http_user_agent'}, {'string': 'request_id', 'replacement': '$request_id'}, {'string': 'nginx_version', 'replacement': '$nginx_version'}, {'string': 'document_root', 'replacement': '$document_root'}, {'string': 'proxied_for_ip', 'replacement': '$http_x_forwarded_for'}], 'once': False}}, {'core': {'listen': [{'port': 8082}], 'server_name': 'localhost'}, 'log': {'access': [{'path': '/var/log/nginx/access.log', 'format': 'main'}]}, 'locations': [{'location': '/', 'core': {'root': '/usr/share/nginx/html', 'index': 'server_two.html'}}], 'sub_filter': {'sub_filters': [{'string': 'server_hostname', 'replacement': '$hostname'}, {'string': 'server_address', 'replacement': '$server_addr:$server_port'}, {'string': 'server_url', 'replacement': '$request_uri'}, {'string': 'remote_addr', 'replacement': '$remote_addr:$remote_port'}, {'string': 'server_date', 'replacement': '$time_local'}, {'string': 'client_browser', 'replacement': '$http_user_agent'}, {'string': 'request_id', 'replacement': '$request_id'}, {'string': 'nginx_version', 'replacement': '$nginx_version'}, {'string': 'document_root', 'replacement': '$document_root'}, {'string': 'proxied_for_ip', 'replacement': '$http_x_forwarded_for'}], 'once': False}}]}}) => {"ansible_loop_var": "item", "changed": false, "item": {"config": {"servers": [{"core": {"listen": [{"port": 80}], "server_name": "localhost"}, "locations": [{"location": "/", "proxy": {"pass": "http://upstr/", "set_header": {"field": "Host", "value": "$host"}}}], "log": {"access": [{"format": "main", "path": "/var/log/nginx/access.log"}]}}, {"core": {"listen": [{"port": 8081}], "server_name": "localhost"}, "locations": [{"core": {"index": "server_one.html", "root": "/usr/share/nginx/html"}, "location": "/"}], "log": {"access": [{"format": "main", "path": "/var/log/nginx/access.log"}]}, "sub_filter": {"once": false, "sub_filters": [{"replacement": "$hostname", "string": "server_hostname"}, {"replacement": "$server_addr:$server_port", "string": "server_address"}, {"replacement": "$request_uri", "string": "server_url"}, {"replacement": "$remote_addr:$remote_port", "string": "remote_addr"}, {"replacement": "$time_local", "string": "server_date"}, {"replacement": "$http_user_agent", "string": "client_browser"}, {"replacement": "$request_id", "string": "request_id"}, {"replacement": "$nginx_version", "string": "nginx_version"}, {"replacement": "$document_root", "string": "document_root"}, {"replacement": "$http_x_forwarded_for", "string": "proxied_for_ip"}]}}, {"core": {"listen": [{"port": 8082}], "server_name": "localhost"}, "locations": [{"core": {"index": "server_two.html", "root": "/usr/share/nginx/html"}, "location": "/"}], "log": {"access": [{"format": "main", "path": "/var/log/nginx/access.log"}]}, "sub_filter": {"once": false, "sub_filters": [{"replacement": "$hostname", "string": "server_hostname"}, {"replacement": "$server_addr:$server_port", "string": "server_address"}, {"replacement": "$request_uri", "string": "server_url"}, {"replacement": "$remote_addr:$remote_port", "string": "remote_addr"}, {"replacement": "$time_local", "string": "server_date"}, {"replacement": "$http_user_agent", "string": "client_browser"}, {"replacement": "$request_id", "string": "request_id"}, {"replacement": "$nginx_version", "string": "nginx_version"}, {"replacement": "$document_root", "string": "document_root"}, {"replacement": "$http_x_forwarded_for", "string": "proxied_for_ip"}]}}], "upstreams": [{"least_conn": true, "name": "upstr", "servers": [{"address": "0.0.0.0:8081"}, {"address": "0.0.0.0:8082"}]}]}, "deployment_location": "/etc/nginx/conf.d/default.conf", "template_file": "http/default.conf.j2"}, "msg": "TemplateAssertionError: no test named 'boolean'"}
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/ansible/plugins/action/template.py", line 146, in run
resultant = templar.do_template(template_data, preserve_trailing_newlines=True, escape_backslashes=False)
File "/usr/local/lib/python3.6/site-packages/ansible/template/__init__.py", line 1100, in do_template
res = j2_concat(rf)
File "<template>", line 43, in root
File "/usr/lib/python3.6/site-packages/jinja2/environment.py", line 830, in get_template
return self._load_template(name, self.make_globals(globals))
File "/usr/lib/python3.6/site-packages/jinja2/environment.py", line 804, in _load_template
template = self.loader.load(self, name, globals)
File "/usr/lib/python3.6/site-packages/jinja2/loaders.py", line 125, in load
code = environment.compile(source, name, filename)
File "/usr/lib/python3.6/site-packages/jinja2/environment.py", line 591, in compile
self.handle_exception(exc_info, source_hint=source_hint)
File "/usr/lib/python3.6/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/lib/python3.6/site-packages/jinja2/_compat.py", line 37, in reraise
raise value.with_traceback(tb)
File "/opt/ansible/collections/ansible_collections/nginxinc/nginx_core/roles/nginx_config/templates/http/upstream.j2", line 16, in template
{{- ' backup' if server['backup'] is defined and server['backup'] is boolean and server['backup'] | bool -}}
File "/usr/lib/python3.6/site-packages/jinja2/environment.py", line 543, in _generate
optimized=self.optimized)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 82, in generate
generator.visit(node)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 754, in visit_Template
self.blockvisit(node.body, frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 378, in blockvisit
self.visit(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1176, in visit_Macro
macro_frame, macro_ref = self.macro_body(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 575, in macro_body
self.blockvisit(node.body, frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 378, in blockvisit
self.visit(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1122, in visit_For
self.blockvisit(node.body, loop_frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 378, in blockvisit
self.visit(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1160, in visit_If
self.blockvisit(node.body, if_frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 378, in blockvisit
self.visit(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1160, in visit_If
self.blockvisit(node.body, if_frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 378, in blockvisit
self.visit(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1122, in visit_For
self.blockvisit(node.body, loop_frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 378, in blockvisit
self.visit(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1160, in visit_If
self.blockvisit(node.body, if_frame)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 378, in blockvisit
self.visit(node, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1314, in visit_Output
self.visit(item, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 70, in new_func
return f(self, node, frame, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1624, in visit_CondExpr
self.visit(node.test, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 70, in new_func
return f(self, node, frame, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1482, in visitor
self.visit(node.left, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 70, in new_func
return f(self, node, frame, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1484, in visitor
self.visit(node.right, frame)
File "/usr/lib/python3.6/site-packages/jinja2/visitor.py", line 38, in visit
return f(node, *args, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 70, in new_func
return f(self, node, frame, **kwargs)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 1607, in visit_Test
self.fail('no test named %r' % node.name, node.lineno)
File "/usr/lib/python3.6/site-packages/jinja2/compiler.py", line 315, in fail
raise TemplateAssertionError(msg, lineno, self.name, self.filename)
jinja2.exceptions.TemplateAssertionError: no test named 'boolean'
failed: [host.fqdn] (item={'template_file': 'http/default.conf.j2', 'deployment_location': '/etc/nginx/conf.d/default.conf', 'config': {'upstreams': [{'name': 'upstr', 'least_conn': True, 'servers': [{'address': '0.0.0.0:8081'}, {'address': '0.0.0.0:8082'}]}], 'servers': [{'core': {'listen': [{'port': 80}], 'server_name': 'localhost'}, 'log': {'access': [{'path': '/var/log/nginx/access.log', 'format': 'main'}]}, 'locations': [{'location': '/', 'proxy': {'pass': 'http://upstr/', 'set_header': {'field': 'Host', 'value': '$host'}}}]}, {'core': {'listen': [{'port': 8081}], 'server_name': 'localhost'}, 'log': {'access': [{'path': '/var/log/nginx/access.log', 'format': 'main'}]}, 'locations': [{'location': '/', 'core': {'root': '/usr/share/nginx/html', 'index': 'server_one.html'}}], 'sub_filter': {'sub_filters': [{'string': 'server_hostname', 'replacement': '$hostname'}, {'string': 'server_address', 'replacement': '$server_addr:$server_port'}, {'string': 'server_url', 'replacement': '$request_uri'}, {'string': 'remote_addr', 'replacement': '$remote_addr:$remote_port'}, {'string': 'server_date', 'replacement': '$time_local'}, {'string': 'client_browser', 'replacement': '$http_user_agent'}, {'string': 'request_id', 'replacement': '$request_id'}, {'string': 'nginx_version', 'replacement': '$nginx_version'}, {'string': 'document_root', 'replacement': '$document_root'}, {'string': 'proxied_for_ip', 'replacement': '$http_x_forwarded_for'}], 'once': False}}, {'core': {'listen': [{'port': 8082}], 'server_name': 'localhost'}, 'log': {'access': [{'path': '/var/log/nginx/access.log', 'format': 'main'}]}, 'locations': [{'location': '/', 'core': {'root': '/usr/share/nginx/html', 'index': 'server_two.html'}}], 'sub_filter': {'sub_filters': [{'string': 'server_hostname', 'replacement': '$hostname'}, {'string': 'server_address', 'replacement': '$server_addr:$server_port'}, {'string': 'server_url', 'replacement': '$request_uri'}, {'string': 'remote_addr', 'replacement': '$remote_addr:$remote_port'}, {'string': 'server_date', 'replacement': '$time_local'}, {'string': 'client_browser', 'replacement': '$http_user_agent'}, {'string': 'request_id', 'replacement': '$request_id'}, {'string': 'nginx_version', 'replacement': '$nginx_version'}, {'string': 'document_root', 'replacement': '$document_root'}, {'string': 'proxied_for_ip', 'replacement': '$http_x_forwarded_for'}], 'once': False}}]}}) => {
"ansible_loop_var": "item",
"changed": false,
"item": {
"config": {
"servers": [
{
"core": {
"listen": [
{
"port": 80
}
],
"server_name": "localhost"
},
"locations": [
{
"location": "/",
"proxy": {
"pass": "http://upstr/",
"set_header": {
"field": "Host",
"value": "$host"
}
}
}
],
"log": {
"access": [
{
"format": "main",
"path": "/var/log/nginx/access.log"
}
]
}
},
{
"core": {
"listen": [
{
"port": 8081
}
],
"server_name": "localhost"
},
"locations": [
{
"core": {
"index": "server_one.html",
"root": "/usr/share/nginx/html"
},
"location": "/"
}
],
"log": {
"access": [
{
"format": "main",
"path": "/var/log/nginx/access.log"
}
]
},
"sub_filter": {
"once": false,
"sub_filters": [
{
"replacement": "$hostname",
"string": "server_hostname"
},
{
"replacement": "$server_addr:$server_port",
"string": "server_address"
},
{
"replacement": "$request_uri",
"string": "server_url"
},
{
"replacement": "$remote_addr:$remote_port",
"string": "remote_addr"
},
{
"replacement": "$time_local",
"string": "server_date"
},
{
"replacement": "$http_user_agent",
"string": "client_browser"
},
{
"replacement": "$request_id",
"string": "request_id"
},
{
"replacement": "$nginx_version",
"string": "nginx_version"
},
{
"replacement": "$document_root",
"string": "document_root"
},
{
"replacement": "$http_x_forwarded_for",
"string": "proxied_for_ip"
}
]
}
},
{
"core": {
"listen": [
{
"port": 8082
}
],
"server_name": "localhost"
},
"locations": [
{
"core": {
"index": "server_two.html",
"root": "/usr/share/nginx/html"
},
"location": "/"
}
],
"log": {
"access": [
{
"format": "main",
"path": "/var/log/nginx/access.log"
}
]
},
"sub_filter": {
"once": false,
"sub_filters": [
{
"replacement": "$hostname",
"string": "server_hostname"
},
{
"replacement": "$server_addr:$server_port",
"string": "server_address"
},
{
"replacement": "$request_uri",
"string": "server_url"
},
{
"replacement": "$remote_addr:$remote_port",
"string": "remote_addr"
},
{
"replacement": "$time_local",
"string": "server_date"
},
{
"replacement": "$http_user_agent",
"string": "client_browser"
},
{
"replacement": "$request_id",
"string": "request_id"
},
{
"replacement": "$nginx_version",
"string": "nginx_version"
},
{
"replacement": "$document_root",
"string": "document_root"
},
{
"replacement": "$http_x_forwarded_for",
"string": "proxied_for_ip"
}
]
}
}
],
"upstreams": [
{
"least_conn": true,
"name": "upstr",
"servers": [
{
"address": "0.0.0.0:8081"
},
{
"address": "0.0.0.0:8082"
}
]
}
]
},
"deployment_location": "/etc/nginx/conf.d/default.conf",
"template_file": "http/default.conf.j2"
},
"msg": "TemplateAssertionError: no test named 'boolean'"
}
Steps to reproduce the behavior:
TASK [nginxinc.nginx_core.nginx_config : Dynamically generate NGINX HTTP config files]
Successful deployment
Collection installed via:
# ansible-galaxy collection install nginxinc.nginx_core
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://galaxy.ansible.com/download/nginxinc-nginx_core-0.4.0.tar.gz to ~/.ansible/tmp/ansible-local-138554ko34z3om/tmpbfjxdsv7/nginxinc-nginx_core-0.4.0-_7gl1uhk
Installing 'nginxinc.nginx_core:0.4.0' to '~/.ansible/collections/ansible_collections/nginxinc/nginx_core'
nginxinc.nginx_core:0.4.0 was installed successfully
ansible [core 2.11.6]
python version = 3.6.8 (default, Sep 12 2021, 04:40:35) [GCC 8.4.1 20200928 (Red Hat 8.4.1-1)]
jinja version = 2.10.1
libyaml = True
NAME="CentOS Stream"
VERSION="8"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Stream 8"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://centos.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_SUPPORT_PRODUCT_VERSION="CentOS Stream"
Add any other context about the problem here.
Can't apply configuration when the http section is enabled. I get the following error:
"AnsibleUndefinedVariable: the inline if-expression on line 9 in 'http/grpc.j2' evaluated to false and no else section was defined."}
The configuration has been copied from this example:
https://github.com/nginxinc/ansible-role-nginx-config/blob/main/molecule/default/converge.yml
Steps to reproduce the behavior:
# https://github.com/nginxinc/ansible-role-nginx
- name: Install NGINX
include_role:
name: nginxinc.nginx
vars:
nginx_install_from: os_repository
nginx_start: false
nginx_type: opensource
nginx_state: present
# https://github.com/nginxinc/ansible-role-nginx-config
- name: Configure NGINX
include_role:
name: nginxinc.nginx_config
vars:
nginx_config_start: false
nginx_config_cleanup: true
nginx_config_debug_output: true
nginx_config_debug_tasks: true
# top level nginx configuration
nginx_config_main_template_enable: true
nginx_config_main_template:
template_file: nginx.conf.j2
conf_file_name: nginx.conf
conf_file_location: /etc/nginx/
worker_connections: 1024
http_custom_includes:
- "/etc/nginx/sites-enabled/*.conf"
user: www-data
worker_processes: auto
pid: /var/run/nginx.pid
# http configuration section
http_enable: true
http_settings:
grpc_global:
bind:
address: $remote_addr
transparent: false
buffer_size: 4k
connect_timeout: 60s
[...]
I expected the configuration to apply without errors
Add any other context about the problem here.
Describe the bug
All listen records inside nginx_http_template.[default].servers.[server1].listen.[listen_items]
won't preserve their insertion position/order inside array dict.
To reproduce
nginx_http_template:
default:
servers:
server1:
listen:
listen_ipv4_http:
ip: "1.2.3.4"
port: 80
opts:
- default_server
- deferred
listen_ipv4_https:
ip: "1.2.3.4"
port: 443
ssl: true
opts:
- http2
- default_server
- deferred
listen_ipv4_front:
ip: "1.2.3.4"
port: 5757
opts:
- default_server
listen_ipv6_http1:
ip: "[fe80::a00:abcd::aaaa]"
port: 80
opts:
- default_server
- deferred
listen_ipv6_http2:
ip: "[fe80::a00:abcd::bbbb]"
port: 80
opts:
- default_server
- deferred
listen_ipv6_https1:
ip: "[fe80::a00:abcd::aaaa]"
port: 443
ssl: true
opts:
- http2
- default_server
- deferred
listen_ipv6_https2:
ip: "[fe80::a00:abcd::bbbb]"
port: 443
ssl: true
opts:
- http2
- default_server
- deferred
listen_ipv6_front:
ip: "[fe80::a00:abcd::cccc]"
port: 5757
opts:
- default_server
Expected result
listen 1.2.3.4:80 default_server deferred;
listen 1.2.3.4:443 ssl http2 default_server deferred;
listen 1.2.3.4:5757 default_server;
listen [fe80::a00:abcd::aaaa]:80 default_server deferred;
listen [fe80::a00:abcd::bbbb]:80 default_server deferred;
listen [fe80::a00:abcd::aaaa]:443 ssl http2 default_server deferred;
listen [fe80::a00:abcd::bbbb]:443 ssl http2 default_server deferred;
listen [fe80::a00:abcd::cccc]:5757 default_server;
Actual result
listen 1.2.3.4:80 default_server deferred;
listen [fe80::a00:abcd::cccc]:5757 default_server;
listen [fe80::a00:abcd::aaaa]:443 ssl http2 default_server deferred;
listen [fe80::a00:abcd::bbbb]:443 ssl http2 default_server deferred;
listen 1.2.3.4:443 ssl http2 default_server deferred;
listen [fe80::a00:abcd::bbbb]:80 default_server deferred;
listen [fe80::a00:abcd::aaaa]:80 default_server deferred;
listen 1.2.3.4:5757 default_server;
Your environment:
Additional context
As far as I know, this is because that the keys in dict
do not preserve their order, and because of this they can be displayed with a random order.
Some additional info: ansible/ansible#36886, ansible/ansible#36644
This issue would not have happened if a list
was used instead of a dict
, for example:
listen:
- ip: "1.2.3.4"
port: 80
opts:
- default_server
- deferred
- ip: "1.2.3.4"
port: 443
ssl: true
opts:
- http2
- default_server
- deferred
instead of:
listen:
listen_ipv4_http:
ip: "1.2.3.4"
port: 80
opts:
- default_server
- deferred
listen_ipv4_https:
ip: "1.2.3.4"
port: 443
ssl: true
opts:
- http2
- default_server
- deferred
But this will be a BC.
Any ideas how we can keep listen directives in their insertion order? Because if there are several listen directives, the order of the lines in the finished default.conf looks weird, and you can get confused in it while trying to understood.
Is your feature request related to a problem? Please describe.
i have an infrastructure that have production applications use grpc and currently automation for them is able to be done only by using a custom template.
so this is the problem - the only way to automate grpc with nginx is to use custom options which is barely readable and hard to support in that case or though making your own template.
Describe the solution you'd like
i would like nginx role to add an options to template to use grpc directives from grpc module https://nginx.org/en/docs/http/ngx_http_grpc_module.html#directives
Describe alternatives you've considered
have separate template specifically for grpc but it complicates things since it is still a part of 'http'
Additional context
I wanted to download the github code using the ansible-galaxy
(cluster) joan@DESKTOP-OM8Q4NE:~/Abzu/cluster$ ansible-galaxy collection install git+https://github.com/nginxinc/ansible-role-nginx-config.git
Cloning into '/home/joan/.ansible/tmp/ansible-local-260469n7zryua/tmp5t1xuas1/ansible-role-nginx-confignf_aip1s'...
remote: Enumerating objects: 1193, done.
remote: Counting objects: 100% (405/405), done.
remote: Compressing objects: 100% (215/215), done.
remote: Total 1193 (delta 245), reused 296 (delta 176), pack-reused 788
Receiving objects: 100% (1193/1193), 296.46 KiB | 2.18 MiB/s, done.
Resolving deltas: 100% (673/673), done.
Your branch is up to date with 'origin/main'.
Starting galaxy collection install process
Process install dependency map
ERROR! Neither the collection requirement entry key 'name', nor 'source' point to a concrete resolvable collection artifact. Also 'name' is not an FQCN. A valid collection name must be in the format <namespace>.<collection>. Please
make sure that the namespace and the collection name contain characters from [a-zA-Z0-9_] only.
Tip: Make sure you are pointing to the right subdirectory — `/home/joan/.ansible/tmp/ansible-local-260469n7zryua/tmp5t1xuas1/ansible-role-nginx-confignf_aip1s` looks like a directory but it is neither a collection, nor a namespace d
ir.
Having a galaxy.yml in the root repo as described in https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html
I'm always frustrated when I need to use the collection and specify custom paths in nginx.conf and need to manage them with custom task. Example:
I want to add to /etc/nginx/nginx.conf
client_body_temp_path /var/nginx/client_body_temp;
This directory is /var/nginx
not created and have not found a way to create custom configs using this role.
Add a role variable that would allow creation of custom dirs.
A clear and concise description of any alternative solutions or features you've considered.
Add any other context or screenshots about the feature request here.
Is your feature request related to a problem? Please describe.
Kind of. I wish to terminate ssl with nginx, and simultaneously apply it as reverse proxy. I do not see an example of this in the docs, even I think it is pretty common scenario.
Describe the solution you'd like
Just an example configuration on how to terminate ssl with reverse proxy
Describe alternatives you've considered
I've considered applying nginx reverse proxy with ssl termination without this role. Like just manually configuring nginx, if it is too hard with this.
I am trying to override juste one setting (server_names_hash_bucket_size
) in the default main template.
Comments in the file state "# Defaults are the values found in a fresh NGINX installation." so I thought enabling nginx_config_main_template_enable
and just overriding the right subkey would do the trick as it would keep the others values.
This didn't work, so I commented out my modification about the custom setting and tried to apply the role with only nginx_config_main_template_enable
set to true
but it fails as well.
Using the role with nginx_config_main_template_enable
set to true
fails with default role values.
Steps to reproduce the behavior:
- name: NGINX
hosts: nginx
debugger: on_failed
become: true
pre_tasks:
- name: Enabling nginx_config_main_template
set_fact:
nginx_config_main_template_enable: true
roles:
- role: nginxinc.nginx
- role: nginxinc.nginx-config
TASK [nginxinc.nginx-config : Dynamically generate NGINX main configuration file] ***********************************************************************************************************
task path: /home/xxx/ansible/yyy/roles/nginxinc.nginx-config/tasks/config/template-config.yml:37
fatal: [nginx_0]: FAILED! => {
"changed": false,
"msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'dest'"
}
I don't have any more info on which 'dict object' it fails on, as the task Dynamically generate NGINX main configuration file
has fallback default values for the dest file (/etc/nginx/nginx.conf
) and thus shouldn't fail.
Comments say "# Defaults are the values found in a fresh NGINX installation." so it should create a standard nginx.conf
file with default values.
ansible 2.9.17
2.11.2
Debian Buster
Describe the bug
The nginx role fails on "(Setup: All OSs) Remove NGINX Configuration Files" with the given error message:
fatal: [playground.example.com]: FAILED! => { "msg": "Unexpected templating type error occurred on ({{ nginx_config_files.results | default('') | map(attribute='files') | sum(start=[]) | map(attribute='path') | list + nginx_cleanup_config_files | default('') }}): can only concatenate list (not \"str\") to list" }
To reproduce
Steps to reproduce the behavior:
Expected behavior
The role proceeds through this step as always and does not stall provisioning.
Your environment:
Additional context
I'm not sure if it helps, but the machine executing the playbook is running ubuntu 20.04 LTS. The role was working flawless until my recent (1 day ago) --force install of all galaxy obtained roles.
The code that should trigger a conf.d/*.conf cleanup is not cleaning up
Steps to reproduce the behavior:
nginx_config_cleanup : '{{ my_cleanup }}'
# this clean up only happens if the above variable is true
nginx_config_cleanup_paths:
- directory:
- /etc/nginx/conf.d
recurse: false
nginx_config_cleanup_files:
- /etc/nginx/conf.d/default.conf
TASK [nginxinc.nginx_config : Find NGINX config files] ************************************************************************************************************************************************************************************************************************
ok: [testing-snap05.MYDOMAIN.TLD] => (item={'directory': ['/etc/nginx/conf.d'], 'recurse': False}) => {"ansible_loop_var": "item", "changed": false, "examined": 13, "files": [{"atime": 1616512425.5879788, "ctime": 1616512425.0159645, "dev": 64780, "gid": 0, "gr_name": "root", "inode": 652034, "isblk": false, "ischr": false, "isdir": false, "isfifo": false, "isgid": false, "islnk": false, "isreg": true, "issock": false, "isuid": false, "mode": "0644", "mtime": 1616512424.6879563, "nlink": 1, "path": "/etc/nginx/conf.d/testing-snap05.staging.MYDOMAIN.TLDX.conf", "pw_name": "root", "rgrp": true, "roth": true, "rusr": true, "size": 508, "uid": 0, "wgrp": false, "woth": false, "wusr": true, "xgrp": false, "xoth": false, "xusr": false}, {"atime": 1616511920.0872648, "ctime": 1616511919.343246, "dev": 64780, "gid": 0, "gr_name": "root", "inode": 652037, "isblk": false, "ischr": false, "isdir": false, "isfifo": false, "isgid": false, "islnk": false, "isreg": true, "issock": false, "isuid": false, "mode": "0644", "mtime": 1616511918.9712367, "nlink": 1, "path": "/etc/nginx/conf.d/testing-snap05.staging.MYDOMAIN.TLD.conf", "pw_name": "root", "rgrp": true, "roth": true, "rusr": true, "size": 507, "uid": 0, "wgrp": false, "woth": false, "wusr": true, "xgrp": false, "xoth": false, "xusr": false}, {"atime": 1616512481.8013923, "ctime": 1616512481.229378, "dev": 64780, "gid": 0, "gr_name": "root", "inode": 652039, "isblk": false, "ischr": false, "isdir": false, "isfifo": false, "isgid": false, "islnk": false, "isreg": true, "issock": false, "isuid": false, "mode": "0644", "mtime": 1616512480.8773692, "nlink": 1, "path": "/etc/nginx/conf.d/testing-snap05.staging.MYDOMAIN.TLDZ.conf", "pw_name": "root", "rgrp": true, "roth": true, "rusr": true, "size": 508, "uid": 0, "wgrp": false, "woth": false, "wusr": true, "xgrp": false, "xoth": false, "xusr": false}, {"atime": 1616512450.800613, "ctime": 1616512450.1845973, "dev": 64780, "gid": 0, "gr_name": "root", "inode": 652038, "isblk": false, "ischr": false, "isdir": false, "isfifo": false, "isgid": false, "islnk": false, "isreg": true, "issock": false, "isuid": false, "mode": "0644", "mtime": 1616512449.8325884, "nlink": 1, "path": "/etc/nginx/conf.d/testing-snap05.staging.MYDOMAIN.TLDY.conf", "pw_name": "root", "rgrp": true, "roth": true, "rusr": true, "size": 508, "uid": 0, "wgrp": false, "woth": false, "wusr": true, "xgrp": false, "xoth": false, "xusr": false}], "item": {"directory": ["/etc/nginx/conf.d"], "recurse": false}, "matched": 4, "msg": ""}
TASK [nginxinc.nginx_config : Remove NGINX config files] **********************************************************************************************************************************************************************************************************************
ok: [testing-snap05.MYDOMAIN.TLD] => (item=/etc/nginx/conf.d/default.conf) => {"ansible_loop_var": "item", "changed": false, "item": "/etc/nginx/conf.d/default.conf", "path": "/etc/nginx/conf.d/default.conf", "state": "absent"}
I expected /etc/nginx/conf.d/*.conf to be deleted before new flies are created. But only default.conf is deleted.
ansible-role-nginx-config from git
nginxinc.nginx, 0.19.1
ansible: 2.9.6+dfsg-1
ubuntu 20.04
There does not appear to be a way to add an alias
directive to the config templates. I have a set of docs I'd like to host at www.server.tld/docs, where the docs are in an arbitrarily named directory created via sphinx. Let's say /some/path/to/_build/html
.
The alias
directive let's me do this:
location /docs {
alias /some/path/to/_build
}
I'd like to be able to add an alias directive. The html_file_location
variable allows setting the root
directive but there is no corresponding variable for the alias
directive.
The alternatives would be to create an intermediary processing step to move the docs from the sphinx directory to a parent directory named 'docs' so the root
directive could be used.
From what I can tell, alias
is is acceptable to route requests to "other" directories on the filesystem different from the main root of the server. If that's intentionally blocked from usage with ansible, would be good to know.
Thanks!
Is your feature request related to a problem? Please describe.
Is there any way to undo any changes done to the main nginx.conf
(go back to original)? I was testing the nginx_main_template
options as I couldn't get port 80 to run my app, but I later discovered that using default_server
for listen opts will also work.
But now, I'm not sure how to undo all of those changes.
Describe the solution you'd like
I should be able to restore the original nginx.conf
.
Describe alternatives you've considered
I can live with the current conf, but I don't like all the vars I have set just to be able to run the app on port 80.
Additional context
No additional context.
If you want to change only the NGINX user, while keeping defaults for other vars, you still have to define all the vars under nginx_main_template
dict.
With those vars:
nginx_main_template_enable: true
nginx_main_template:
user: www-data
It causes the following error:
TASK [nginxinc.nginx : (Setup: All NGINX) Dynamically Generate NGINX Main Configuration File] ************************
fatal: [sandbox]: FAILED! => {"changed": false, "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'worker_processes'"}
We should be allowed to define only some vars, and keep defaults for the other ones.
This is not a bug. Just a question on basic usage. New to Ansible and nginx.
Steps to reproduce the behavior:
I want to change default root path (Apache-ism is DocumentRoot) from /usr/share/nginx/html to /var/www/html. I know the config file to change would be /etc/nginx/conf.d/default.conf
and the section:
location / {
root /var/www/html;
index index.html index.htm;
}
But I can't seem to get a single change from my playbook. I'm experimenting with another issue I saw here in the github issues. I'm experimenting with this --but it does nothing.
I realize this won't change location /
--but it's just a starting point.
This is how I run the playbook: ansible-playbook nginxinc.nginx_config.yml -K
nginxinc.nginx_config.yml:
- hosts: testing
become: true
roles:
- {role: nginxinc.nginx_config}
vars:
# nginx_config_debug_output: true
nginx_config_http_template:
- template_file: http/default.conf.j2
conf_file_name: 50_example.com.conf
conf_file_location: /etc/nginx/conf.d/
servers:
- listen:
- port: 8080
-
Could you show me an example of how to change location / { root /var/www/html; ...
None.
Unless I misunderstood the spirit of this:
https://github.com/nginxinc/ansible-role-nginx-config/blob/main/templates/http/default.conf.j2
https://github.com/nginxinc/ansible-role-nginx-config/blob/main/defaults/main/template.yml
I thought a proxy: section inside:
nginx_config_main_template:
http_settings:
would allow the definition of
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_read_timeout 90s;
proxy_buffers 32 4k
Steps to reproduce the behavior:
A clear and concise description of what you expected to happen.
nginxinc.nginx_config, 0.3.3
nginxinc.nginx, 0.19.1
ansible: 2.9.6+dfsg-1
ubuntu 20.04
I apologize if I misunderstood something :-)
Describe the bug
The following code is not working. https_redirect is a boolean in the check, but needs to be a string for the config template
{% if item.value.servers[server].https_redirect is defined and item.value.servers[server].https_redirect %}
return 301 https://{{ item.value.servers[server].https_redirect }}$request_uri;
{% endif %}
Is your feature request related to a problem? Please describe.
The playbook I am developing using this role requires the use of ip_hash
in upstream {}
blocks. It does not currently seem to be supported.
Describe the solution you'd like
I would like to have support for the ip_hash
directive added to the http/default.conf.j2
template. I may open a PR myself to fix this issue given enough spare time.
Describe alternatives you've considered
I have considered manually copying and altering the template file default.conf.j2 but decided it would be best if this is fixed upstream.
Additional context
Example:
upstream some_name {
ip_hash;
server 10.10.10.10;
server 10.20.20.20;
}
Note: I erroneously submitted the template issue by accident after changing the issue type.
Comments in the commit history indicate that for nginx_config_main_template, the child variables conf_file_name and conf_file_location have been replaced by deployment_location. This appears to be only partially implemented. The code still looks for the removed variables:
https://github.com/nginxinc/ansible-role-nginx-config/blob/0.4.0/tasks/config/template-config.yml#L32
https://github.com/nginxinc/ansible-role-nginx-config/blob/0.4.0/tasks/config/template-config.yml#L60
If your folder is anything other than the default, it won't get created.
{{ ... | dirname }}
on the deployment_location to extract the directory nameTo install nginx I use my own RPM repository (for CentOS 7/8). This is necessary because standard repositories (CentOS and the official nginx RPM repository) lack many necessary modules, for example https://github.com/leev/ngx_http_geoip2_module, https://github.com/google/ngx_brotli and a few else. Therefore, instead of compiling the nginx right on the production server, I build it locally and distribute it through my RPM repository, which was installed via pre_tasks
before executing this role.
Is your feature request related to a problem? Please describe.
Now we can install only those modules for which separate tasks have been created: njs, perl, waf (Nginx Plus), geoip (RHEL < 8), image_filter, rtmp (Nginx Plus), xslt.
But we are not able to install any other module, since there is no task to install the list of extra packages.
Describe the solution you'd like
All tasks for all operating systems must be changes to install any extra package BEFORE starting/restarting/reloading nginx. This must be some sort of
- name: "(Install: Linux) Install additional Package"
package:
name: "{{ nginx_additional_packages }}"
state: "{{ nginx_state }}"
when: nginx_install_from == "os_repository" # ???
notify: "(Handler: All OSs) Reload NGINX"
Additional context
pre_tasks
, because they will require nginx
package, which wasn' installed at this moment.tasks
or post_tasks
, because nginx.conf
will contain loading of these modules via load_module "modules/ngx_http_geoip2_module.so";
, so nginx won't be restarted correctly when this role will notify
about this.There is a second problem here, since neither the CentOS repositories nor the official nginx repos contain any other modules. From the ansible side, this will look exactly the same as if you set nginx_install_from == "os_repository"
, which means "do not install official nginx repository, just install package nginx
with the system package manager".
There will be no problems here as long as there is package nginx
in the system or my own repositories. But what if we distribute our package with a different name, for example nginx-custom
, so that when updating the packages via yum update
, we do not accidentally install package nginx
from some other repositories, which may have a version higher than in my own repository.
Therefore, we need some way to specify the name of the nginx
package, and, accordingly, all the modules for it (like package nginx-custom
and modules nginx-custom-module-geoip2
).
I want to propose a new way to reuse and maintain templates.
Jinja2 supports template inheritance, current templates could be split into small blocks and put them in a higher one with {% include '../small-part.j2'%}
For example, i create folder lib/upstream.block.j2 with:
{% if item.value.upstreams is defined and item.value.upstreams %}
{% for upstream in item.value.upstreams %}
upstream {{ item.value.upstreams[upstream].name }} {
{% if item.value.upstreams[upstream].lb_method is defined and item.value.upstreams[upstream].lb_method | length %}
{{ item.value.upstreams[upstream].lb_method }};
{% endif %}
{% if item.value.upstreams[upstream].zone_name is defined and item.value.upstreams[upstream].zone_name %}
zone {{ item.value.upstreams[upstream].zone_name }} {{ item.value.upstreams[upstream].zone_size }};
{% endif %}
{% for server in item.value.upstreams[upstream].servers %}
server {{ item.value.upstreams[upstream].servers[server].address }}:{{ item.value.upstreams[upstream].servers[server].port }} weight={{ item.value.upstreams[upstream].servers[server].weight|default("1") }} {{ item.value.upstreams[upstream].servers[server].health_check|default("") }};
{% endfor %}
{% if item.value.upstreams[upstream].sticky_cookie %}
sticky cookie srv_id expires=1h path=/;
{% endif %}
{% if item.value.upstreams[upstream].custom_options is defined and item.value.upstreams[upstream].custom_options | length %}
{% for inline_option in item.value.upstreams[upstream].custom_options %}
{{ inline_option }};
{% endfor %}
{% endif %}
}
{% endfor %}
{% endif %}
And refactor the files http/default.conf.j2
and stream/default.conf.j2
with:
{# http/default.conf.j2 #}
{{ ansible_managed | comment }}
{% include '../lib/upstream.block.j2' %}
....
{# stream/default.conf.j2 #}
{{ ansible_managed | comment }}
{% include '../lib/upstream.block.j2' %}
....
It will also allow to build your own configurations using blocks without rewriting everything. If it is an interesting functionality i can do a pull request with the changes to see more details.
Is your feature request related to a problem? Please describe.
It would be really handy to be able to upload a snippets
directory containing configuration files, so that one can reuse common configuration in other nginx http conf files. If I'm not mistaken, I don't believe that this is currently (explicitly) possible in this plugin.
Describe alternatives you've considered
Tried using nginx_main_upload_src
and nginx_http_upload_src
, but neither work in this case. nginx_main_upload_src
expects a file, and nginx_http_upload_src
uses fileglob
, which does not allow for recursive copies.
I could obviously do this in a separate role, but it would be nice to have all the nginx configuration done in the same role.
Describe the solution you'd like
One solution would be to emulate existing upload variable options, such as nginx_http_upload_enable
. For example, introducing the vars: nginx_snippets_upload_enable
, as well as src
and dest
counterparts would be nice.
If you feel that this solution is too specific to snippets
, perhaps there is a more general way to copy local files to the root of the remote nginx directory. This is sort of how it's done in this Ansible nginx plugin: https://github.com/tschifftner/ansible-role-nginx#use-additional-nginx-templates
Alternatively making it possible to recursively possible to upload directories to the http config directory would be another way to go, though I'm not a fan of this as it doesn't match the defacto nginx directory structure, where snippets
is on the root.
Thanks!
Is your feature request related to a problem? Please describe.
I painfully came up with a raw nginx conf for a simple old domain / uri scheme to new one
server {
listen 0.0.0.0:80;
server_name documentation.old.domain;
rewrite (.*).html(.*) $1$2;
rewrite (.*)/en/stable(.*) $1$2;
return 301 https://new.domain/uc-doc$uri;
}
I can't implement this one.
Describe the solution you'd like
Something that work. Outside of a homemade raw Ansible copy:
Describe alternatives you've considered
Tried quickly, ended up with this mess that's never gonna work with the rewrite after the proxy pass (or so I believe)
listen 0.0.0.0:80;
server_name documentation.old.domain;
location ^ {
proxy_pass https://new.domain/uc-doc;
rewrite rewrite (.*).html(.*) $1$2;;
rewrite rewrite (.*)/en/stable(.*) $1$2;;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Good day!
In your file "defaults/main/template.yml" there is "load_module" list :
nginx_config_main_template:
config:
main:
load_module: modules/ngx_http_js_module.so
In my nginx configuration, there is no real file "ngx_http_js_module.so" in file system.
So I have error during role run.
I don't want to change your role files by removing "load_module: modules" element from dictionary.
How can I disable/omit this step in playbook ? Probably by re-setting "load_module" variable for "empty/undefined" value in playbook. To avoid such errors.
Thank you for your work for community!
BTW: do you have the support for sites-available/sites-enabled config file structure?
It seems impossible to use the include
(doc) directive directly in nginx.conf
(aka using nginx_config_main_template
with default.conf.j2
), which is sad because of Debian's /etc/nginx/modules-available/
and /etc/nginx/modules-enabled/
directories.
I always had a nginx.conf
like this :
xxx
include /etc/nginx/modules-enabled/*.conf;
events {
xxx
}
http {
include /etc/nginx/mime.types;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
I'd like to add support to the include
keyword in default.conf.j2
.
I tried to use include /etc/nginx/modules-enabled/*.conf;
directly in http
config (aka inside nginx_config_http_template
), but the load_modules directive can't be used inside http
entries, so that's not possible.
I currently list all my modules like this :
# cat modules-enabled/*
load_module modules/ngx_http_auth_pam_module.so;
load_module modules/ngx_http_dav_ext_module.so;
load_module modules/ngx_http_echo_module.so;
load_module modules/ngx_http_geoip_module.so;
load_module modules/ngx_http_image_filter_module.so;
load_module modules/ngx_http_subs_filter_module.so;
load_module modules/ngx_http_upstream_fair_module.so;
load_module modules/ngx_http_xslt_filter_module.so;
load_module modules/ngx_mail_module.so;
load_module modules/ngx_stream_module.so;
And then list all modules inside of the load_module
directive :
load_module:
- modules/ngx_http_auth_pam_module.so
- modules/ngx_http_dav_ext_module.so
- modules/ngx_http_echo_module.so
- modules/ngx_http_geoip_module.so
- modules/ngx_http_image_filter_module.so
- modules/ngx_http_subs_filter_module.so
- modules/ngx_http_upstream_fair_module.so
- modules/ngx_http_xslt_filter_module.so
- modules/ngx_mail_module.so
- modules/ngx_stream_module.so
But I lose the possibility to remove symlinks in modules-enabled
+ restart nginx for disabling a module.
N/A
PS : Thanks for this amazing role !
Describe the bug
When running ansible-playbook --check (or -C) there is an error reporting config
dict has no attribute rc
FAILED! => {"msg": "The conditional check 'config.rc != 0' failed. The error was: error while evaluating conditional (config.rc != 0): 'dict object' has no attribute 'rc'\n\nThe error appears to be in '/Users/<myname>/.ansible/roles/nginxinc.nginx_config/handlers/main.yml': line 9, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: (Handler - NGINX Config) Print NGINX error if syntax check fails\n ^ here\n"}
This section of code will always fail in check mode, because the task (Handler - NGINX Config) Check NGINX
is skipped and config.rc
will never exist.
- name: (Handler - NGINX Config) Check NGINX
command: nginx -t
register: config
ignore_errors: yes
changed_when: false
listen: (Handler - NGINX Config) Run NGINX
- name: (Handler - NGINX Config) Print NGINX error if syntax check fails
debug:
var: config.stderr_lines
failed_when: config.rc != 0
when: config.rc != 0
listen: (Handler - NGINX Config) Run NGINX
All template calls use backup: yes
, for example:
Steps to reproduce the behavior:
/etc/nginx/conf.d/
directory for example; this will have a lot of backup filesWhile having backup files is fine, it should be opt-out
Is this expected behavior? Or would you like an option where this is set from a var(iable)?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.