I’ve documented what eventually worked for me.
In summary. This is n8n powered by docker and docker-compose with nginx installed locally using apt.
The Nginx part
My complete nginx configuration looks like this:
upstream myserver {
server 127.0.0.1:5678;
keepalive 64;
}
server {
server_name n8n.example.com;
location / {
proxy_pass http://myserver;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
# note the inclusion of the protocol 'https'
add_header Access-Control-Allow-Origin https://my.website.example.com;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
}
# this is leftover from another example
# isn't really needed for the cors stuff
client_max_body_size 25m;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = myn8n.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name n8n.example.com;
listen 80;
return 404; # managed by Certbot
}
The n8n part
I use the docker-compose from the n8n server setup docs
“misdirect” traefik on purpose
I modified the docker-compose example to have traefik listen on different ports because I want to use nginx as the proxy. It really is my way of removing traefik from ports 80 and 443. I’ll eventually remove it from my setup.
While I was testing I made traefik listen on ports 1080 and 1443 (again, I plan to just remove the traefik service).
version: "3"
services:
traefik:
image: "traefik:v2.4"
restart: always
command:
- "--api=true"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
- "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
ports:
- "1080:80"
- "1443:443"
volumes:
- ${DATA_FOLDER}/letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
Once again, this was a quick fix, very akin to adding a comment in source code, I fully intend to just remove the traefik service.
gotchas
setting headers with the webhook nodes
I know it is possible to set headers (e.g Access-Control-Allow-Origin headers) on the n8n provided webhook nodes themselves, but this caused all sorts of conflicts for me. I had situations where the proxy and the webhook in n8n set the same header (instant conflict). When I removed the headers from the proxy, for some reason, the webhook headers did not show up. In the long run I settled for setting the header using the proxy.
setting blank header will kill you
At one point I was completely stuck, the nginx proxy had the correct header and I thought the webhook node had removed the header. When I inspected the webhook node it had a blank header set. This made requests to the webhook “hang”
Access-Control-Allow-Headers is important
The way CORS works there are some headers that are not allowed, unless the proxy explicitly allows them.
Hence this line in my nginx config
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'
I know for sure that the Content-Type
header was a problem for me. I added the others because they were recommended in tutorials on the internet. I suspect some of them aren’t needed.