From 25b54aba2b43d3e54a513541e7811fe6d6080f4f Mon Sep 17 00:00:00 2001 From: = Date: Fri, 5 Sep 2025 14:22:50 +0200 Subject: [PATCH] Initial commit --- .env.sample | 14 +++ .gitignore | 4 + Makefile | 274 +++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 95 ++++++++++++++++ init-data.sh | 13 +++ 5 files changed, 400 insertions(+) create mode 100644 .env.sample create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 docker-compose.yml create mode 100755 init-data.sh diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..663e2e3 --- /dev/null +++ b/.env.sample @@ -0,0 +1,14 @@ +VHOST=n8n.lc +VPORT=5678 + +N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true + +POSTGRES_USER=root +POSTGRES_PASSWORD=passwd +POSTGRES_DB=n8n + +POSTGRES_NON_ROOT_USER=n8n_user +POSTGRES_NON_ROOT_PASSWORD=passwd + +ENCRYPTION_KEY=changeEncryptionKey +DOCKER_ENV=local diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..baf5bf8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +db_storage +n8n_storage +redis_storage diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d4c1c14 --- /dev/null +++ b/Makefile @@ -0,0 +1,274 @@ +## +# Makefile to help manage docker-compose services +# +# Built on top of those resources: +# https://gist.github.com/iNamik/cafef08f9d931cbf7acb012075052912 +# https://github.com/krom/docker-compose-makefile/tree/master/samples +# + +# Include environment files +include .env +export + +# Other variables +THIS_FILE := Makefile +DOCKER := docker +DOCKER_COMPOSE := docker-compose + +DOCKER_COMPOSE_FILES := -f docker-compose.yml +ifeq ($(DOCKER_ENV),staging) + DOCKER_COMPOSE_FILES := -f docker-compose.yml +endif +ifeq ($(DOCKER_ENV),production) + DOCKER_COMPOSE_FILES := -f docker-compose.yml +endif + +CERT_DOMAIN := $(VHOST) + +IMAGE_DEFAULT := n8n +CONTAINER_DEFAULT := n8n-n8n-1 + +SERVICES_DEFAULT := n8n postgres redis n8n-worker +ifeq ($(DOCKER_ENV),staging) + SERVICES_DEFAULT := n8n postgres redis n8n-worker +endif +ifeq ($(DOCKER_ENV),production) + SERVICES_DEFAULT := n8n postgres redis n8n-worker +endif + +SERVICE_DEFAULT := n8n + +NETWORK := ollama + +BACKUP_SERVICE := backup +RESTORE_SERVICE := restore + +SHELL_CMD := /bin/bash + +container ?= $(CONTAINER_DEFAULT) +image ?= $(IMAGE_DEFAULT) +service ?= +services ?= $(SERVICES_DEFAULT) + +.DEFAULT_GOAL := help + + +## +# help +# +help: +ifeq ($(CONTAINER_DEFAULT),) + $(warning WARNING: CONTAINER_DEFAULT is not set. Please edit makefile) +endif + @echo + @echo "Make targets:" + @echo + @cat $(THIS_FILE) | \ + sed -n -E 's/^([^.][^: ]+)\s*:(([^=#]*##\s*(.*[^[:space:]])\s*)|[^=].*)$$/ \1 \4/p' | \ + sort -u | \ + expand -t15 + @echo + @echo + @echo "Target arguments:" + @echo + @echo " " "service" "\t" "Target service for docker-compose actions (default=all-services)" + @echo " " " " "\t" " - make start" + @echo " " " " "\t" " - make start services=app" + @echo " " "services" "\t" "Target services for docker-compose actions (default=all-services, space separated)" + @echo " " " " "\t" " - make stop services='app mysql'" + @echo " " "container""\t" "Target container for docker actions (default='$(CONTAINER_DEFAULT)')" + @echo " " " " "\t" " - make bash container=$(container)" + @echo " " "image" "\t" "Target image for interactive shell (default='$(IMAGE_DEFAULT)')" + @echo " " " " "\t" " - make it image=$(image)" + + +## +# services +# +services: ## Lists services + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) ps --services + + +## +# start +# +all: dev ## See 'dev' +start: dev ## See 'dev' +dev: ## Start containers for development [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) up -d $(services) + $(MAKE) logs + + +## +# stop +# +stop: ## Stop containers [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) stop $(services) + + +## +# restart +# +restart: ## Restart containers [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) restart $(services) + + +## +# down +# +down: ## Removes containers (preserves images and volumes) + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) down + + +create-network: +ifeq ($(DOCKER_ENV),local) + @echo + @echo "Creating proper network ($(NETWORK)) for the project" + @$(DOCKER) network create $(NETWORK) 2> /dev/null || true +endif + + +## +# build +# +build: create-network ## Builds service images [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) build $(services) + + +## +# rebuild +# +rebuild: ## Build containers without cache [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) build --no-cache $(services) + + +## +# ps +# +status: ps ## See 'ps' +ps: ## Show status of containers + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) ps + + +## +# interact +# +interact: it ## See `it' +it: ## Run a new container in interactive mode. Needs image name [image] +ifeq ($(image),) + $(error ERROR: 'image' is not set. Please provide 'image=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Starting interactive shell ($(SHELL_CMD)) in image container '$(image)'" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) run -i --no-deps --entrypoint "$(SHELL_CMD)" $(image) + + +## +# bash +# +sh: bash ## See 'bash' +shell: bash ## See 'bash' +bash: ## Brings up a shell in default (or specified) container [container] +ifeq ($(container),) + $(error ERROR: 'container' is not set. Please provide 'container=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Starting shell ($(SHELL_CMD)) in container '$(container)'" + @$(DOCKER) exec -it "$(container)" "$(SHELL_CMD)" + + +## +# attach +# +at: attach ## See 'attach' +attach: ## Attach to a running container [container] +ifeq ($(container),) + $(error ERROR: 'container' is not set. Please provide 'container=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Attaching to '$(container)'" + @$(DOCKER) attach $(container) + + +## +# log +# +log: ## Shows log from a specific container (in 'follow' mode) [container] +ifeq ($(container),) + $(error ERROR: 'container' is not set. Please provide 'container=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Log in $(container)" + @$(DOCKER) logs -f $(container) + + +## +# logs +# +logs: ## Shows output of running containers (in 'follow' mode) [service|services] + @echo + @echo "Logs in $(services)" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) logs -f $(services) + + +## +# rmimages +# +rmimages: ## Remove images + @echo + @echo "Remove local images" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) down --rmi local + + +## +# rmvols +# +rmvols: ## Remove volumes + @echo + @echo "Remove named volumes declared in the volumes section of the Compose file and anonymous volumes attached to containers" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) down -v + + +## +# rm +# +rm: rmimages rmvols ## Remove volumes and images + +## +# clean +# +clean: ## Remove containers, images and volumes + @echo + @echo "Remove containers, images and volumes" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) down --volumes --rmi all + + +## +# backup +# +backup: ## Run 'backup' service + @echo + @echo "Running '$(BACKUP_SERVICE)'" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) run $(BACKUP_SERVICE) + + +## +# restore +# +restore: ## Run 'restore' service + @echo + @echo "Running '$(BACKUP_SERVICE)'" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) run $(RESTORE_SERVICE) + + +## +# dumplog +# +dumplog: ## Run 'dumplog' [service|services] + if [ ! -d "_data/logs" ]; then mkdir -p "_data/logs"; fi + @echo + @echo "Running 'dumplog'" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) logs --no-color --since 24h --timestamps $(services) + + +.PHONY: help services all start dev stop restart down create-network build rebuild status ps interact it sh shell bash at attach log logs rm rmimages rmvols clean backup restore dumplog diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4d600f8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,95 @@ +x-shared: &shared + restart: always + image: docker.n8n.io/n8nio/n8n + environment: + - DB_TYPE=postgresdb + - DB_POSTGRESDB_HOST=postgres + - DB_POSTGRESDB_PORT=5432 + - DB_POSTGRESDB_DATABASE=${POSTGRES_DB} + - DB_POSTGRESDB_USER=${POSTGRES_NON_ROOT_USER} + - DB_POSTGRESDB_PASSWORD=${POSTGRES_NON_ROOT_PASSWORD} + - EXECUTIONS_MODE=queue + - QUEUE_BULL_REDIS_HOST=redis + - QUEUE_HEALTH_CHECK_ACTIVE=true + - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY} + links: + - postgres + - redis + volumes: + - ./n8n_storage:/home/node/.n8n + depends_on: + redis: + condition: service_healthy + postgres: + condition: service_healthy + +services: + postgres: + image: postgres:16 + restart: always + environment: + - POSTGRES_USER + - POSTGRES_PASSWORD + - POSTGRES_DB + - POSTGRES_NON_ROOT_USER + - POSTGRES_NON_ROOT_PASSWORD + volumes: + - ./db_storage:/var/lib/postgresql/data + - ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh + healthcheck: + test: ['CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}'] + interval: 5s + timeout: 5s + retries: 10 + networks: + - n8n + + redis: + image: redis:6-alpine + restart: always + volumes: + - ./redis_storage:/data + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + interval: 5s + timeout: 5s + retries: 10 + networks: + - n8n + + n8n: + <<: *shared + ports: + - ${VPORT}:${VPORT} + environment: + - N8N_HOST=${VHOST} + - N8N_PORT=${VPORT} + - N8N_PROTOCOL=https + - NODE_ENV=production + - N8N_PATH + - WEBHOOK_URL=https://${VHOST}${N8N_PATH} + labels: + - 'traefik.enable=true' + - 'traefik.http.routers.n8n.rule=Host(`${VHOST}`)' + - 'traefik.http.routers.n8n.service=n8n-service' + - 'traefik.http.routers.n8n.entrypoints=websecure' + - 'traefik.http.routers.n8n.tls=true' + - 'traefik.http.services.n8n-service.loadbalancer.server.port=${VPORT}' + networks: + - default + - n8n + + n8n-worker: + <<: *shared + command: worker + depends_on: + - n8n + networks: + - n8n + +networks: + default: + name: nginx-proxy + external: true + n8n: + driver: bridge diff --git a/init-data.sh b/init-data.sh new file mode 100755 index 0000000..f98a972 --- /dev/null +++ b/init-data.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e; + + +if [ -n "${POSTGRES_NON_ROOT_USER:-}" ] && [ -n "${POSTGRES_NON_ROOT_PASSWORD:-}" ]; then + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL + CREATE USER ${POSTGRES_NON_ROOT_USER} WITH PASSWORD '${POSTGRES_NON_ROOT_PASSWORD}'; + GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO ${POSTGRES_NON_ROOT_USER}; + GRANT CREATE ON SCHEMA public TO ${POSTGRES_NON_ROOT_USER}; + EOSQL +else + echo "SETUP INFO: No Environment variables given!" +fi