Initial commit

This commit is contained in:
Joaquín de Santiago 2025-09-05 14:22:50 +02:00
commit 25b54aba2b
5 changed files with 400 additions and 0 deletions

14
.env.sample Normal file
View File

@ -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

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.env
db_storage
n8n_storage
redis_storage

274
Makefile Normal file
View File

@ -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

95
docker-compose.yml Normal file
View File

@ -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

13
init-data.sh Executable file
View File

@ -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