diff --git a/services/n8n/.env-example b/services/n8n/.env-example new file mode 100644 index 0000000..f64cbc6 --- /dev/null +++ b/services/n8n/.env-example @@ -0,0 +1,30 @@ +#version=1.1 +#URL=https://github.com/tailscale-dev/ScaleTail +#COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure. + +# Service Configuration +SERVICE=n8n +IMAGE_URL=docker.n8n.io/n8nio/n8n:stable +TAILNET_NAME= + +# Network Configuration +SERVICEPORT=5678 # N8N default port +DNS_SERVER=9.9.9.9 + +# Tailscale Configuration +TS_AUTHKEY= + +# Optional Service variables +# PUID=1000 + +# N8N Configuration variables +POSTGRES_USER= +POSTGRES_PASSWORD= +POSTGRES_DB= + +POSTGRES_NON_ROOT_USER= +POSTGRES_NON_ROOT_PASSWORD= + +N8N_ENCRYPTION_KEY= + +TZ=Europe/London \ No newline at end of file diff --git a/services/n8n/README.md b/services/n8n/README.md new file mode 100644 index 0000000..74b7a1c --- /dev/null +++ b/services/n8n/README.md @@ -0,0 +1,37 @@ +# SERVICE with Tailscale Sidecar Configuration + +This Docker Compose configuration sets up [N8N](https://n8n.io/) with Tailscale as a sidecar container to keep the app reachable over your Tailnet. + +## SERVICE + +[N8N](https://n8n.io/) a workflow automation platform that uniquely combines AI capabilities with business process automation, giving technical teams the flexibility of code with the speed of no code. + +## Configuration Overview + +In this setup, the `tailscale-N8N` service runs Tailscale, which manages secure networking for SERVICE. The `SERVICE` service utilizes the Tailscale network stack via Docker's `network_mode: service:` configuration. This keeps the app Tailnet-only unless you intentionally expose ports. + +For the folder structure you will need to pre-create the n8n-storage directory, and correct the ownership before the first run, by doing the following: + +```bash +mkdir -p n8n-storage +sudo chown -R 1000:1000 n8n-storage +``` + +## What to document for users + +In this setup, the tailscale-n8n service runs Tailscale, which manages secure networking for the N8N service. The N8N service uses the Tailscale network stack via Docker’s network_mode: service: configuration. This setup ensures that N8N management interface is only accessible through the Tailscale network (or locally, if preferred), providing an extra layer of security and privacy for managing your automations. + +If you need the runners for N8N uncomment the following within the docker-compose.yaml file - `N8N_RUNNERS_MODE=external`, `N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN}`, `N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0` as well as uncommenting `RUNNERS_AUTH_TOKEN` within the .env file. + +The configs section also needs to be updated to match the below. Specifically the Proxy port needs changing from 8080 to 5678 + +``` +configs: + ts-serve: + content: | + {"TCP":{"443":{"HTTPS":true}}, + "Web":{"$${TS_CERT_DOMAIN}:443": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:5678"}}}}, + "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}} +``` \ No newline at end of file diff --git a/services/n8n/docker-compose.yml b/services/n8n/docker-compose.yml new file mode 100644 index 0000000..bbad4d1 --- /dev/null +++ b/services/n8n/docker-compose.yml @@ -0,0 +1,104 @@ +configs: + ts-serve: + content: | + {"TCP":{"443":{"HTTPS":true}}, + "Web":{"$${TS_CERT_DOMAIN}:443": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:5678"}}}}, + "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}} + +services: + # Make sure you have updated/checked the .env file with the correct variables. + # All the ${ xx } need to be defined there. + # Tailscale Sidecar Configuration + tailscale: + image: tailscale/tailscale:latest # Image to be used + container_name: tailscale-${SERVICE} # Name for local container management + hostname: ${SERVICE} # Name used within your Tailscale environment + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json # Tailscale Serve configuration to expose the web interface on your local Tailnet - remove this line if not required + - TS_USERSPACE=false + - TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz" + - TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The : for the healthz endpoint + #- TS_ACCEPT_DNS=true # Uncomment when using MagicDNS + - TS_AUTH_ONCE=true + configs: + - source: ts-serve + target: /config/serve.json + volumes: + - ./config:/config # Config folder used to store Tailscale files - you may need to change the path + - ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path + devices: + - /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work + cap_add: + - net_admin # Tailscale requirement + #ports: + # - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT} # Binding port ${SERVICE}PORT to the local network - may be removed if only exposure to your Tailnet is required + # If any DNS issues arise, use your preferred DNS provider by uncommenting the config below + # dns: + # - ${DNS_SERVER} + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 10s # Time to wait before starting health checks + restart: always + + postgres: + container_name: n8n-postgres + image: postgres:16 + restart: always + environment: + - POSTGRES_USER + - POSTGRES_PASSWORD + - POSTGRES_DB + - POSTGRES_NON_ROOT_USER + - POSTGRES_NON_ROOT_PASSWORD + volumes: + - ./${SERVICE}-db:/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 + + application: + image: ${IMAGE_URL} + network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale + container_name: app-${SERVICE} + restart: unless-stopped + #ports: + # - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT} # Binding port ${SERVICE}PORT to the local network - may be removed if only exposure to your Tailnet is required + # If any DNS issues arise, use your preferred DNS provider by uncommenting the config below + #dns: + # - ${DNS_SERVER} + volumes: + - ./${SERVICE}-storage:/home/node/.n8n + environment: + - N8N_HOST=n8n.${TAILNET_NAME} + - N8N_PORT=5678 + - N8N_PROTOCOL=https + - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} + - N8N_RUNNERS_ENABLED=true + - N8N_BLOCK_ENV_ACCESS_IN_NODE=true + - N8N_GIT_NODE_DISABLE_BARE_REPOS=true + - NODE_ENV=production + - WEBHOOK_URL=https://${TAILNET_NAME}/ + - 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} + # - N8N_RUNNERS_MODE=external + # - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN} + # - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0 + links: + - postgres + depends_on: + postgres: + condition: service_healthy