Proxying Zotonic with nginx
It is possible to put Zotonic behind the nginx <http://nginx.org/> web server, for example if you have other, non-Zotonic virtual hosts running on your system.
When proxying, don’t forget to check the config files of the sites you
are planning to server (the apps_user/yoursite/priv/zotonic_site.config
files). The hostname
value should not contain any port number, if
you run from port 80/443: {hostname, "test.zotonic.com"}
.
Zotonic configuration
Example of zotonic.config
(find the location using bin/zotonic configfiles
) ip/port
settings when terminating SSL in nginx proxy and using plain HTTP towards the Zotonic
backend:
%%% IP address on which Zotonic will listen for HTTP requests.
{listen_ip, any},
%%% Port on which Zotonic will listen for HTTP requests.
{listen_port, 8000},
%%% Port on which Zotonic will listen for HTTPS requests.
%%% Set to the atom 'none' to disable SSL
{ssl_listen_port, none},
%%% Outside port on which Zotonic will listen for HTTP requests.
{port, 80},
%%% Outside port zotonic uses to receive incoming HTTPS requests.
{ssl_port, 443},
Nginx configuration
Below is an example configuration file to proxy nginx to zotonic. Be
sure to replace all occurrences of test.zotonic.com
with your own
hostname:
server {
listen 80;
listen [::]:80 default_server ipv6only=on; ## listen for ipv6
listen 443 ssl http2;
listen [::]:443 ssl http2 ipv6only=on;
server_name test.zotonic.com;
access_log /var/log/nginx/test.zotonic.com.access.log;
error_log /var/log/nginx/test.zotonic.com.error.log;
keepalive_timeout 65;
gzip off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA128:DHE-RSA-AES128-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA128:ECDHE-RSA-AES128-SHA384:ECDHE-RSA-AES128-SHA128:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA384:AES128-GCM-SHA128:AES128-SHA128:AES128-SHA128:AES128-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_prefer_server_ciphers on;
# Disable preloading HSTS for now. Enable when you know that your
# server certs works. You can use the header line that includes
# the "preload" directive if you understand the implications.
# add_header Strict-Transport-Security "max-age=15768000; includeSubdomains"; # six months
# add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
# create with: openssl dhparam -out /etc/nginx/dhparam.pem 2048
# ssl_dhparam /etc/nginx/dhparam.pem;
ssl_certificate /path/to/ssl.crt;
ssl_certificate_key /path/to/ssl.key;
location / {
proxy_pass http://127.0.0.1:8000/;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass_request_headers on;
client_max_body_size 0;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
location /mqtt-transport {
proxy_pass http://127.0.0.1:8000/mqtt-transport;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass_request_headers on;
}
location /close-connection {
keepalive_timeout 0;
empty_gif;
}
}
As shown in the example above:
- Add
X-Forwarded-Proto
to proxied header so that Zotonic knows that HTTPS is used before the proxy even though HTTP is used between the proxy and backend. - Add
X-Real-IP
andX-Forwarded-For
headers.
Zotonic always redirects to HTTPS so the proxy needs to be configured for both HTTP and HTTPS.
Zotonic makes use of a websocket connection for MQTT messages at the
/mqtt-transport
endpoint, so you need to pass the Upgrade
and Connection
headers.
The /mqtt-transport
endpoint is also used to POST uploaded files
using a HTML multi-part form post.
See the nginx documentation for more information on its configuration procedure.