La documentation d’installation de n8n utilise Traefik comme reverse proxy, mais j’ai souhaité tester n8n et j’utilise Nginx et j’ai donc repris l’installation initiale et je l’ai modifié selon mon besoin et je souhaite la partager.

Structure


├── _configuration
│   └── nginx
│       └── n8n.com.conf
├── docker-compose.yml
├── Dockerfile
├── .env
├── shared
│   └── .gitkeep
└── Makefile

Environment

Créer le ficiher .env et renseigner les valeurs comme indiqué :

DOMAIN_NAME=domain.tld
SUBDOMAIN=subdomain
GENERIC_TIMEZONE=Europe/Paris
SSL_EMAIL=admin@domain.tld
CONTAINER_NAME=container_name

Docker

Docker compose

Créer le fichier docker-compose.yml.

services:
  n8n:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        UID: ${UID:-1000}
        GID: ${GID:-1000}
    container_name: n8n
    restart: always
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
    volumes:
      - n8n_data:/home/node/.n8n
      - n8n_files:/files
      - ./shared:/shared:ro

volumes:
  n8n_data:
  n8n_files:

Dockerfile

Créer le fichier Docker.
Sur le serveur que j’utilise, le user n’est pas celui qui a le UID=1000 et GID=100 j’ai donc ajouté un condition afin de permettre de gérer ce cas.

FROM docker.n8n.io/n8nio/n8n

ARG UID
ARG GID

USER root

# Because the user may be different, a dedicated user must be created and linked to host user GID/UID
RUN if [ "$GID" != "$(id -g node)" ]; then \
        addgroup -g $GID appuser && \
        adduser -D -u $UID -G appuser appuser && \
        addgroup node appuser; \
    fi

USER node

Nginx

server {
    listen      80;
    server_name subdomain.domain.tld;
    return 301 https://subdomain.domain.tld$request_uri;
}

server {
    listen      443 ssl http2;
    server_name subdomain.domain.tld;

    ssl_certificate  /etc/letsencrypt/live/subdomain.domain.tld/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/subdomain.domain.tld/privkey.pem;

    location ^~ /.well-known {
        allow all;
        auth_basic off;
        root /path/to/create/certs/.certs/;
    }

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_set_header Upgrade $http_upgrade; # Added for WebSocket
        proxy_set_header Connection "Upgrade"; # Modified for WebSocket
        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;
        chunked_transfer_encoding off;
        proxy_buffering off;
        proxy_cache off;
        proxy_http_version 1.1;
    }

    error_log /var/log/nginx/error_n8n.log;
    access_log /var/log/nginx/access_n8n.log;

    include conf.d/httpd.conf;
    include conf.d/gzip.conf;
    include conf.d/proxy.conf;
}

Makefile

Oui encore un fichier Makefile, n’en déplaise à certains, mais je trouve ça très pratique.

ifneq (,$(wildcard ./.env))
	include .env
	export
endif

ifeq (, $(which -v docker-compose))
	DOCKER_COMPOSE = docker compose
else
	DOCKER_COMPOSE = docker-compose
endif

MAKEFLAGS += --always-make
ARGS ?= $(strip $(subst =,\\=,$(subst ',\\',$(subst ",\\",$(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))))))

# Misc
.DEFAULT_GOAL = help
.PHONY = help

## -- Docker Makefile --
help: ## Outputs this help screen
	@grep -E '(^[a-zA-Z0-9_-]+:.*?##.*$$)|(^##)' $(firstword $(MAKEFILE_LIST)) | \
    awk 'BEGIN {FS = ":.*?## "}{printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}'

## -- Docker --
.PHONY = up
up: ## Build the images and start the containers
	@COMPOSE_BAKE=true $(DOCKER_COMPOSE) up -d --build --force-recreate

.PHONY = down
down: ## Stop the docker hub
	@$(DOCKER_COMPOSE) down --remove-orphans

.PHONY = start
start: ## Start containers
	@$(DOCKER_COMPOSE) start

.PHONY = stop
stop: ## Stop containers
	@$(DOCKER_COMPOSE) stop

## -- Shell --
.PHONY = shell
shell: ## Run into container
	@docker exec -ti "$(CONTAINER_NAME)" sh

## -- Exec --
.PHONY = exec
exec: ## Run exec
	@docker exec -ti "$(CONTAINER_NAME)" $(ARGS)

## -- Logging
logs: ## Log php container
	@docker logs "$(CONTAINER_NAME)" --follow

# Avoid to build argument as a target
%::
	@true

et voilà

Maintenant il suffit de lancer la commande pour créer le container

make up

Le dossier shared permet de partager des fichiers entre le host et le container. Quant au dossier files, il permet de manipuler des fichiers qui peuvent être nécessaires pour n8n.