ansible-role-nginx-config
ansible-role-nginx-config copied to clipboard
Example of ssl termination with nginx reverse proxy
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.
You can take the examples and expand them with the dict objects taken from the templates defaults: https://github.com/nginxinc/ansible-role-nginx/blob/master/defaults/main/template.yml
Something like this:
nginx_http_template_enable: true
nginx_http_template:
jira_mydomain_net:
conf_file_name: jira_mydomain_net.conf
servers:
first:
listen:
listen_public:
ip: 0.0.0.0
port: 443
ssl: true
server_name: jira.mydomain.net
ssl:
cert: /etc/ssl/certs/jira.mydomain.net.crt
key: /etc/ssl/private/jira.mydomain.net.key
access_log:
- name: combined
location: /var/log/nginx/jira.mydomain.net_access.log
error_log:
location: /var/log/nginx/jira.mydomain.net_error.log
level: warn
reverse_proxy:
locations:
default:
location: /
proxy_pass: http://jira01.local.mydomain.net:8080
I left out ssl ciphers, dhparam, proxy_set_header etc since I set them in the main config, but you can just take them from the examples or defaults. Same for using upstreams.
@xTrekStorex is totally right. At some stage I would also like to have working examples for most use cases covered in Molecule playbooks, including SSL (using self-signed certs) if possible.
I am trying to generate this config below with no luck. I wonder if its supported.
location /app1/ { proxy_pass http://localhost:6000; } location /app2/ { proxy_pass http://localhost:5000; }
Should definitely work. Are you using the latest release or main? If on main, check https://github.com/nginxinc/ansible-role-nginx-config/blob/main/molecule/default/converge.yml#L153-L290 -- you'll see there's two location blocks with proxy_pass
. You can delete all the other variables that are being tested and set the values you mentioned for location
and proxy_pass
. (Side note: might want to create a new issue, your question is not related to ssl
as far as I can tell.)
I am also unable to configure a simple reverse proxy. In the example above I don't recognize the
reverse_proxy:
section.
When I try to use proxy_pass instead of root on a server that I have defined I get
TemplateAssertionError: no test named 'boolean'
A working example would be appreciated.
The reverse_proxy
section no longer exists. It got refactored into the proxy
dictionaries you can now find on main
(and 0.4.0
). Did you check the molecule examples in the previous comment? In addition, proxy_pass
is not allowed within a server context. It always has to be inside a location
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass.
Example:
nginx_config_http_template_enable: true
nginx_config_http_template:
- template_file : http/default.conf.j2
conf_file_name : '{{ my_server_name }}.conf'
conf_file_location: /etc/nginx/conf.d/
servers:
- listen:
- port: 443
ssl : true
opts: []
server_name: '{{ my_server_name }}'
ssl:
cert : '/etc/ssl/certs/{{ my_ssl_prefix }}.nginx.bundle.crt'
key : '/etc/ssl/private/{{ my_ssl_prefix }}.key'
protocols : '{{ NGINX_PROTOCOLS }}'
prefer_server_ciphers: true
ciphers : '{{ NGINX_CIPHERS }}'
stapling : true
stapling_verify : true
autoindex : false
locations :
- location: /
root : '{{ my_root_folder }}'
- location: /backend
proxy_pass: http://127.0.0.1:8080/
proxy:
set_header:
- field: Host
value: $host
- field: X-Real-IP
value: $remote_addr
- field: X-Forwarded-For
value: $proxy_add_x_forwarded_for
- field: X-Forwarded-Proto
value: $scheme
This results in
failed: [testing-snap05.MYDOMAIN.TLD] (item={'template_file': 'http/default.conf.j2', 'conf_file_name': 'testing-snap05.staging.MYDOMAIN.TLD.conf', 'conf_file_location': '/etc/nginx/conf.d/', 'servers': [{'listen': [{'port': 443, 'ssl': True, 'opts': []}], 'server_name': 'testing-snap05.staging.MYDOMAIN.TLD', 'ssl': {'cert': '/etc/ssl/certs/star.staging.MYDOMAIN.TLD.nginx.bundle.crt', 'key': '/etc/ssl/private/star.staging.MYDOMAIN.TLD.key', 'protocols': 'TLSv1.3', 'prefer_server_ciphers': True, 'ciphers': 'HIGH:!aNULL:!MD5', 'stapling': True, 'stapling_verify': True}, 'autoindex': False, 'locations': [{'location': '/', 'root': '/usr/share/nginx/html'}, {'location': '/backend', 'proxy_pass': 'http://127.0.0.1:8080/', 'proxy': {'set_header': [{'field': 'Host', 'value': '$host'}, {'field': 'X-Real-IP', 'value': '$remote_addr'}, {'field': 'X-Forwarded-For', 'value': '$proxy_add_x_forwarded_for'}, {'field': 'X-Forwarded-Proto', 'value': '$scheme'}]}}]}]}) => {"ansible_loop_var": "item", "changed": false, "item": {"conf_file_location": "/etc/nginx/conf.d/", "conf_file_name": "testing-snap05.staging.MYDOMAIN.TLD.conf", "servers": [{"autoindex": false, "listen": [{"opts": [], "port": 443, "ssl": true}], "locations": [{"location": "/", "root": "/usr/share/nginx/html"}, {"location": "/backend", "proxy": {"set_header": [{"field": "Host", "value": "$host"}, {"field": "X-Real-IP", "value": "$remote_addr"}, {"field": "X-Forwarded-For", "value": "$proxy_add_x_forwarded_for"}, {"field": "X-Forwarded-Proto", "value": "$scheme"}]}, "proxy_pass": "http://127.0.0.1:8080/"}], "server_name": "testing-snap05.staging.MYDOMAIN.TLD", "ssl": {"cert": "/etc/ssl/certs/star.staging.MYDOMAIN.TLD.nginx.bundle.crt", "ciphers": "HIGH:!aNULL:!MD5", "key": "/etc/ssl/private/star.staging.MYDOMAIN.TLD.key", "prefer_server_ciphers": true, "protocols": "TLSv1.3", "stapling": true, "stapling_verify": true}}], "template_file": "http/default.conf.j2"}, "msg": "TemplateAssertionError: no test named 'boolean'"}
Right. Try to update to the latest version of Jinja2. The templates require Jinja2 2.11.x
to properly work. This is most likely related to the errors you were finding on https://github.com/nginxinc/ansible-role-nginx-config/issues/94.
Thank you. Does it exist as a package for Ubuntu 20.04? Otherwise what is the recommended update method?
Jinja2 is a Python package. You can try running pip install -U Jinja2
. You can read more here https://jinja.palletsprojects.com/en/2.11.x/intro/#installation
Hello,
Having the same issue on python 2.7 and ansible 2.9.6:
"TemplateAssertionError: no test named 'boolean'"
On python 3.6 and ansible 2.9.6 everything works fine.
Variables:
nginx_config_http_template_enable: 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:
- ip: 0.0.0.0
port: 80
- ip: 0.0.0.0
port: 443
ssl: true
ssl:
cert: /etc/pki/tls/certs/example.com.crt
key: /etc/pki/tls/private/example.com.key
server_name: example.com
error_page: /usr/share/nginx/html
autoindex: false
http_demo_conf: false
access_log:
- name: json
location: /var/log/nginx/example.com-access.json.log
error_log:
level: warn
location: /var/log/nginx/example.com-error.log
locations:
- location: /
proxy_pass: http://127.0.0.1
proxy:
bind: false
set_header:
- field: Host
value: $host
- field: X-Forwarded-For
value: $proxy_add_x_forwarded_for
- field: X-Real-IP
value: $remote_addr
- field: REMOTE_ADDR
value: $remote_addr
Results to:
+#
+# Ansible managed
+#
+
+
+
+
+server {
+ listen 0.0.0.0:80;
+ listen 0.0.0.0:443 ssl;
+ server_name example.com;
+ ssl_certificate /etc/pki/tls/certs/example.com.crt;
+ ssl_certificate_key /etc/pki/tls/private/example.com.key;
+ location / {
+ proxy_bind off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header REMOTE_ADDR $remote_addr;
+
+ proxy_pass http://127.0.0.1;
+
+ }
+ # redirect server error pages to the static page /50x.html
+ #
+ error_page 500 502 503 504 /50x.html;
+ location = /50x.html {
+ root /usr/share/nginx/html;
+ }
+ access_log /var/log/nginx/example.com-access.json.log json;
+ error_log /var/log/nginx/example.com-error.log warn;
+}
Try updating Jinja2. You are not using the latest release (v2.11).
@alessfg Thanks!
There was no red output, so I didn't notice that I'm actually having troubles updating Jinja2 locally:
bash-3.2$ pip install -U Jinja2
Collecting Jinja2
Using cached https://files.pythonhosted.org/packages/7e/c2/1eece8c95ddbc9b1aeb64f5783a9e07a286de42191b7204d67b7496ddf35/Jinja2-2.11.3-py2.py3-none-any.whl
Requirement not upgraded as not directly required: MarkupSafe>=0.23 in /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages (from Jinja2) (0.23)
Installing collected packages: Jinja2
Found existing installation: Jinja2 2.10.1
Uninstalling Jinja2-2.10.1:
Successfully uninstalled Jinja2-2.10.1
Rolling back uninstall of Jinja2
You are using pip version 10.0.0, however version 20.3.4 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
In a clean virtualenv with Python 2.7 and Jinja2 2.11.3 everything works fine:
(py27) bash-3.2$ pip freeze
ansible==2.9.6
cffi==1.14.5
cryptography==3.3.2
enum34==1.1.10
ipaddress==1.0.23
Jinja2==2.11.3
MarkupSafe==1.1.1
pycparser==2.20
PyYAML==5.4.1
six==1.15.0
Just for anyone looking for an currently working example:
v 0.4.0
- template_file: http/default.conf.j2
deployment_location: /etc/nginx/conf.d/name.conf
config:
upstreams:
- name: name_example_com
least_conn: true
servers:
- address: '172.16.20.55:80'
weight: 5
servers:
- core:
listen:
- port: 80
server_name:
- name.example.com
locations:
- location: '/robots.txt'
log_not_found: false # wont get set
access:
allow: 'all'
log:
access: false
- location: '/'
rewrite:
return:
code: 301
url: 'https://$server_name:443$request_uri'
- core:
listen:
- port: 443
ssl: true
http2: true
server_name:
- name.example.com
ssl:
certificate:
- /etc/pki/tls/certs/name.example.com-rsa/name.example.com-rsa-fullchain.pem
- /etc/pki/tls/certs/name.example.com-p-384/name.example.com-p-384-fullchain.pem
certificate_key:
- /etc/pki/tls/private/name.example.com-rsa/name.example.com-rsa.key
- /etc/pki/tls/private/name.example.com-p-384/name.example.com-p-384.key
trusted_certificate: '/etc/pki/tls/certs/name.example.com-p-384/name.example.com-p-384-chain.pem'
dhparam: '/etc/pki/tls/misc/dhparam.crt'
protocols:
- TLSv1.2
- TLSv1.3
ciphers:
- ECDHE-ECDSA-AES128-GCM-SHA256
- ECDHE-RSA-AES128-GCM-SHA256
- ECDHE-ECDSA-AES256-GCM-SHA384
- ECDHE-RSA-AES256-GCM-SHA384
- ECDHE-ECDSA-CHACHA20-POLY1305
- ECDHE-RSA-CHACHA20-POLY1305
- DHE-RSA-AES128-GCM-SHA256
- DHE-RSA-AES256-GCM-SHA384
ecdh_curve:
- secp521r1
- secp384r1
prefer_server_ciphers: false
# stapling: true
# stapling_verify: true
session_cache:
shared:
name: 'SSL'
size: '10m'
session_tickets: true
session_timeout: '1d'
access:
allow:
- 172.16.0.0/12
- 10.255.255.0/24
deny: 'all'
headers:
add_headers:
- name: 'Strict-Transport-Security'
value: '"max-age=63072000"'
always: true
- name: 'X-Frame-Options'
value: '"SAMEORIGIN"'
always: false
add_trailers:
- name: 'Strict-Transport-Security'
value: '"max-age=63072000"'
always: true
- name: 'X-Frame-Options'
value: '"SAMEORIGIN"'
always: false
log:
access:
- path: '/var/log/nginx/name_access.log'
format: 'main'
error:
- /var/log/nginx/name_error.log
locations:
- location: '/'
proxy:
pass: 'http://name_example_com'
connect_timeout: '1s'
bind: false
set_header:
- field: 'Host'
value: '$host'
- field: 'X-Forwarded-For'
value: '$proxy_add_x_forwarded_for'
- field: 'X-Real-IP'
value: '$remote_addr'
- field: 'REMOTE_ADDR'
value: '$remote_addr'
But how do i get an nested location block like this: can anyone help me out? (is that even the best way do configure such location blocks?)
location ^~ /some/dir/ {
location ~ \.json$ {
if ($http_referer != "") {
return 301 https://app.example.com:443/#HTTP_request('GET','https://$server_name:443$request_uri','','Cross-Origin%20Resource%20Sharing',false);
}
proxy_bind off;
proxy_connect_timeout 1s;
proxy_pass http://data_example_com;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE_ADDR $remote_addr;
allow 172.16.0.0/12;
allow 10.255.255.0/24;
deny all;
}
proxy_bind off;
proxy_connect_timeout 1s;
proxy_pass http://data_example_com;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE_ADDR $remote_addr;
allow 172.16.0.0/12;
allow 10.255.255.0/24;
deny all;
}
The role in its current iteration does not allow for nested location blocks. You can probably achieve what you want with a little bit of code duplication by creating two different location blocks. Alternatively, and given that you are also using an if
statement (which is also not supported by the role), maybe check out the custom_directives
parameter? You could potentially include your whole nested location block using that parameter.
Thanks for that reply.
I already utilize custom_directives
for map
and geo
type of configuration.
But i dont came up with the idea to use them for the entire location
block.
This did the trick! THANKS! :)
Just for anyone looking for an currently working example:
v 0.4.0
That's pretty useful!
I feel there's truly a need to have a simple sample configuration here. I tried the above and it just did zlit here. I have the following playbook:
---
- name: Prometheus installation
hosts: prometheus
tasks:
- name: Install NGINX
ansible.builtin.include_role:
name: nginxinc.nginx
vars:
nginx_manage_repo: false
nginx_install_from: "os_repository"
- name: Configure NGINX
ansible.builtin.include_role:
name: nginxinc.nginx_core.nginx_config
vars:
nginx_config_debug_output: false
nginx_config_cleanup: false
nginx_config_http_template_enable: true
nginx_config_http_template:
- template_file: http/default.conf.j2
conf_file_name: prometheus.debian.net.conf
conf_file_location: /etc/nginx/conf.d/
backup: true
servers:
- core:
listen:
- port: 80
- port: 443
ssl: true
server_name:
- prometheus.debian.net
ssl:
certificate:
- /etc/letsencrypt/live/prometheus.debian.net/fullchain.pem
certificate_key:
- /etc/letsencrypt/live/prometheus.debian.net/privkey.pem
server_name: prometheus.debian.net
error_page: /usr/share/nginx/html
autoindex: false
http_demo_conf: false
log:
access:
- path: /var/log/nginx/prometheus.debian.net_access.log
format: combined
error:
- /var/log/nginx/prometheus.debian.net_error.log
locations:
- location: /
proxy:
pass: http://localhost:9090
this doesn't even create a prometheus.debian.net.conf
file anywhere I could find.
I've been pouring through https://github.com/nginxinc/ansible-role-nginx-config/blob/main/molecule/plus/converge.yml and https://github.com/nginxinc/ansible-role-nginx-config/blob/main/molecule/default/converge.yml and those are very verbose, it's quite hard to find my way in there.
So could we please have an up-to-date, minimalist configuration people could derive from? It's really nice to have the full details of all the possible configuration items, but we get totally lost in that YAML file there...
actually, this works now:
---
- name: Prometheus installation
hosts: prometheus
tasks:
- name: Install NGINX
ansible.builtin.include_role:
name: nginxinc.nginx
vars:
nginx_manage_repo: false
nginx_install_from: "os_repository"
- name: Configure NGINX
ansible.builtin.include_role:
name: nginxinc.nginx_core.nginx_config
vars:
nginx_config_http_template_enable: true
nginx_config_http_template:
- template_file: http/default.conf.j2
deployment_location: /etc/nginx/conf.d/prometheus.debian.net.conf
config:
servers:
- core:
listen:
- port: 80
- port: 443
ssl: true
server_name:
- prometheus.debian.net
ssl:
certificate:
- /etc/letsencrypt/live/prometheus.debian.net/fullchain.pem
certificate_key:
- /etc/letsencrypt/live/prometheus.debian.net/privkey.pem
server_name: prometheus.debian.net
log:
access:
- path: /var/log/nginx/prometheus.debian.net_access.log
format: combined
error:
- /var/log/nginx/prometheus.debian.net_error.log
locations:
- location: /
proxy:
pass: http://localhost:9090
that's as minimal as it gets, and i think that something like this should be one of an example directly linked from the readme, if not directly in the readme file...
I agree! Working on/improving how some use cases are documented is one of the next items in my bucket list (I want to adapt the model used in the core nginx role). I can't promise an exact date but hopefully it'll be within the next month 😁