RU RU

Installing n8n on FastPanel with Docker Compose: A Clear Guide

Published on July 3, 2025

In this guide, I’ll show you how to easily install n8n, a powerful workflow automation tool, on your server with FastPanel using Docker Compose. FastPanel is great for managing web servers, and Docker Compose simplifies the deployment of complex applications like n8n with its dependencies (PostgreSQL and Redis).

What You’ll Need

  • Your server with FastPanel installed.
  • A domain or subdomain you’ll use to access n8n (e.g., n8n.yourdomain.com).
  • Basic knowledge of SSH and command line.

Step 1: Prepare the Server

Connect to your server via SSH and create a directory:

sudo mkdir -p /opt/n8n_stack
cd /opt/n8n_stack

Step 2: Create Configuration Files

You’ll need the following files:

  • docker-compose.yml
  • .env
  • init-data.sh
  • healthcheck.js

2.1. docker-compose.yml

nano docker-compose.yml
version: '3.8'

x-shared: &shared
  restart: always
  image: docker.n8n.io/n8nio/n8n:1.91.3
  env_file: .env
  user: "1000:1000"
  volumes:
    - /opt/n8n_stack/n8n_storage:/home/node/.n8n
    - ./healthcheck.js:/healthcheck.js
  depends_on:
    redis:
      condition: service_healthy
    postgres:
      condition: service_healthy

services:
  postgres:
    image: postgres:11
    restart: always
    env_file: .env
    volumes:
      - /opt/n8n_stack/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

  redis:
    image: redis:6-alpine
    restart: always
    volumes:
      - /opt/n8n_stack/redis_storage:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 5s
      timeout: 5s
      retries: 10

  n8n:
    <<: *shared
    ports:
      - "127.0.0.1:5678:5678"
    healthcheck:
      test: ["CMD", "node", "/healthcheck.js"]
      interval: 5s
      timeout: 5s
      retries: 10

  n8n-worker:
    <<: *shared
    command: worker
    depends_on:
      - n8n
    healthcheck:
      test: ["CMD-SHELL", "wget -q -O - http://localhost:5678/healthz || exit 1"]
      interval: 5s
      timeout: 5s
      retries: 10

2.2. .env

nano .env
# n8n
N8N_HOST=your_n8n_domain.com
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://your_n8n_domain.com/
N8N_ENCRYPTION_KEY=your_secure_password_for_n8n
GENERIC_TIMEZONE=Europe/Moscow
TZ=Europe/Moscow
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=your_db_name
DB_POSTGRESDB_USER=your_non_root_db_user
DB_POSTGRESDB_PASSWORD=your_non_root_db_password

# PostgreSQL (root)
POSTGRES_DB=your_db_name
POSTGRES_USER=your_db_user
POSTGRES_PASSWORD=your_db_password

# PostgreSQL (non-root for n8n)
POSTGRES_NON_ROOT_USER=your_non_root_db_user
POSTGRES_NON_ROOT_PASSWORD=your_non_root_db_password

2.3. init-data.sh

nano init-data.sh
#!/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 EXTENSION IF NOT EXISTS "pgcrypto";
        CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
        DO
        \$do\$
        BEGIN
           IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '${POSTGRES_NON_ROOT_USER}') THEN
              CREATE USER "${POSTGRES_NON_ROOT_USER}" WITH PASSWORD '${POSTGRES_NON_ROOT_PASSWORD}';
           ELSE
              ALTER USER "${POSTGRES_NON_ROOT_USER}" WITH PASSWORD '${POSTGRES_NON_ROOT_PASSWORD}';
           END IF;
        END
        \$do\$;
        GRANT ALL PRIVILEGES ON DATABASE "${POSTGRES_DB}" TO "${POSTGRES_NON_ROOT_USER}";
EOSQL
else
    echo "SETUP INFO: Environment variables POSTGRES_NON_ROOT_USER or POSTGRES_NON_ROOT_PASSWORD are not set."
fi
chmod +x init-data.sh

2.4. healthcheck.js

nano healthcheck.js
var http = require('http');

var options = {
  host: '127.0.0.1',
  port: 5678,
  path: '/healthz',
  method: 'GET',
};

var req = http.request(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  process.exit(res.statusCode === 200 ? 0 : 1);
});

req.on('error', function(e) {
  console.log('ERROR: ' + e.message);
  process.exit(1);
});

req.end();

Step 3: Launch n8n with Docker Compose

docker compose up -d

Check the status:

docker compose ps

All services should be in running or healthy status.


Step 4: Configure FastPanel

  1. Go to FastPanel → SitesAdd site.

  2. Use the domain specified in .env (n8n.yourdomain.com).

  3. After creation:

    • Go to site settings.
    • Enable Reverse Proxy.
    • Enter the address: 127.0.0.1:5678.
    • Make sure SSL is issued (usually Let’s Encrypt does it automatically).

WebSocket Support (if needed manually):

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Step 5: Access n8n

Open in your browser:

https://n8n.yourdomain.com

You’ll see the n8n welcome page. Everything is ready — start building automations!


If you have questions or run into issues — feel free to ask in the comments.

Related Posts

Get in touch

Let's discuss your project and find the right solution