After a thorough research and testing process powered by Gemini, I’ve created what I believe to be the definitive guide to a production-ready n8n installation on Ubuntu with Docker. I’ve personally run and verified every step of this process, and I can confirm it works flawlessly. This guide focuses on best practices to ensure your self-hosted n8n instance is secure, reliable, and ready for long-term use.

n8n Installation

The deployment of a self-hosted workflow automation platform, such as n8n, requires a strategic approach that prioritizes security, data integrity, and long-term operational sustainability. While a basic installation can be achieved with minimal effort, a robust, production-grade setup necessitates a more deliberate architecture. This report provides a comprehensive, step-by-step guide to installing n8n on an Ubuntu server using Docker, adhering to industry best practices for a resilient and secure deployment.

Part I: Foundational Architecture and Component Selection

A production-ready n8n stack is not a single container but a collection of interconnected services designed to work in concert. The architectural decisions made at this stage are critical for ensuring the system’s reliability, scalability, and security.

1.1 System Prerequisites and Architectural Decisions

A successful deployment is contingent upon a correctly provisioned host environment. The following prerequisites are considered the foundation for a best-practice installation:

  • A Virtual Private Server (VPS) running a modern version of Ubuntu (e.g., 20.04 or 22.04).
  • A domain name with a DNS A record pointed to the server’s public IP address.
  • Access to the server via SSH as a user with sudo privileges or as the root user.
  • Firewall rules that permit traffic on ports 80 and 443 for public access, as well as port 22 for SSH access. Port 5678 should be blocked from external access and only permitted internally.

The choice to use Docker is a fundamental architectural decision for a production environment. Although alternative methods, such as a direct npm installation, exist, containerization offers significant advantages for self-hosted applications. Docker encapsulates n8n and its dependencies within an isolated, portable container, eliminating conflicts with other applications and simplifying dependency management (e.g., Node.js versions and required build tools). This isolation ensures that n8n runs in a consistent environment, from development to production, which is crucial for reliability and simplifies future maintenance and updates. The use of Docker Compose further streamlines this process by allowing the entire multi-container stack to be defined and managed through a single configuration file.

1.2 The Database: Moving from SQLite to PostgreSQL for Production

By default, a simple docker run command for n8n uses a file-based SQLite database to store all critical data, including workflows, credentials, and execution history. While this approach is adequate for a basic local development or testing environment, it introduces significant risks in a production setting.

The core limitation of SQLite is its lack of robust concurrency handling. In a production environment with concurrent workflow executions, multiple processes or threads will attempt to write to the same database file simultaneously. This can lead to file-locking issues, performance bottlenecks, and, in severe cases, data corruption. Furthermore, scaling a SQLite-based setup is impossible, as the database is a single point of failure that cannot be shared or replicated across multiple machines.

For these reasons, the use of a robust, client-server database is a non-negotiable requirement for a production-ready n8n deployment. PostgreSQL is the widely recommended solution that n8n natively supports. A PostgreSQL server is architecturally designed to manage concurrent transactions and ensure data integrity, providing the stability and reliability required for mission-critical automation workloads. Deploying n8n alongside a dedicated PostgreSQL container using Docker Compose is the established best practice for achieving this level of data durability.

A comparison of the two database options is provided below.

CategorySQLite (Default for Docker Run)PostgreSQL (Recommended for Production)
Use CaseLocal development, simple testingProduction, multi-user environments
ConcurrencyLimited. Prone to file-locking issuesHigh. Architecturally designed for concurrent transactions
Data IntegrityVulnerable to corruption under high loadRobust, ACID-compliant transactions
Backup ComplexityRequires backing up a single fileRequires database-specific tools (pg_dump)
PerformanceSub-optimal for high-I/O or high-concurrency workloadsHigh performance, scalable
RecommendationNot suitable for any long-term or critical use caseRequired for stability and data reliability

1.3 The Reverse Proxy: A Non-Negotiable Security Layer

Directly exposing an application’s internal port (in n8n’s case, port 5678) to the public internet is a significant security vulnerability. This practice bypasses essential security measures and should be avoided in all production scenarios. A reverse proxy serves as an intermediary layer between the public internet and the n8n container, providing a critical set of services that ensure security and correct functionality.

The primary function of a reverse proxy is to handle SSL/TLS encryption. The n8n application uses secure cookies by default, and its webhooks rely on secure communication. Without a reverse proxy configured to provide an HTTPS connection, the n8n web interface may display browser security warnings, and more importantly, webhook functionality, which is essential for triggering workflows from external services, will not operate securely. A reverse proxy also handles port forwarding, routing external requests on standard ports (e.g., 80 and 443) to the internal port of the n8n container.

When selecting a reverse proxy, two of the most popular choices for a Dockerized environment are Nginx and Traefik. Nginx is a mature, battle-tested solution that offers a high degree of manual control through static configuration files. Traefik, on the other hand, is a more modern, container-native solution that automates service discovery and SSL certificate management using Docker labels.

A comparison of Nginx and Traefik is provided below to assist in the selection process.

CategoryNginxTraefik
Configuration StyleManual configuration filesAutomated via Docker labels
Use CaseIdeal for users who prefer granular control over their proxy settingsBest for dynamic environments with multiple services and for simplifying SSL management
Learning CurveModerate; requires knowledge of Nginx syntaxLower for basic use; higher for advanced features
SSL ManagementManual with Certbot (certbot --nginx)Automatic via Docker labels
ProsWell-documented, high performance, powerful for complex setupsHighly automated, simplifies configuration, great for microservices
ConsRequires manual configuration for each new serviceMay have a steeper learning curve for advanced use cases

Part II: The Definitive Step-by-Step Production Deployment

This section provides the explicit, annotated commands and configuration files required to deploy the recommended production stack.

2.1 Step 1: Preparing the Host Environment

The first action is to create a dedicated directory for the n8n project and establish the correct file permissions for persistent data storage. This is a subtle but critical security and operational best practice. The n8n Docker image is configured to run its processes as a non-root user with a User ID (UID) of 1000. For the n8n container to be able to write to the host’s file system, the host directories must be owned by a user with this same UID. Failure to do so will result in permission errors and the container’s inability to start.

First, connect to the server via SSH and create the project directory:

Bash

mkdir ~/n8n && cd ~/n8n

Next, create a subdirectory for n8n’s persistent data and set the correct ownership and permissions.

Bash

mkdir n8n_data
sudo chown -R 1000:1000 n8n_data

This command recursively changes the ownership of the n8n_data directory to the user with UID 1000 and group ID (GID) 1000, ensuring the n8n container can read from and write to its persistent data volume.

2.2 Step 2: Crafting the Production docker-compose.yml

The docker-compose.yml file is the central blueprint for the entire n8n stack. This file defines two key services: db for the PostgreSQL database and n8n for the workflow automation application. The configuration below implements all the architectural best practices discussed in Part I.

Create a new file named docker-compose.yml in the ~/n8n directory using a text editor such as nano.

Bash

sudo nano docker-compose.yml

Paste the following content into the file, ensuring the environment variables are replaced with secure, randomly generated values.

YAML

services:
  db:
    image: postgres:14
    restart: always
    environment:
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=n8npass
      - POSTGRES_DB=n8n
    volumes:
      - postgres_data:/var/lib/postgresql/data
  n8n:
    image: n8nio/n8n
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=n8npass
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=StrongPasswordHere
      - N8N_HOST=n8n.yourdomain.com
      - WEBHOOK_TUNNEL_URL=https://n8n.yourdomain.com
      - N8N_ENCRYPTION_KEY=StrongEncryptionKey
    depends_on:
      - db
    volumes:
      - n8n_data:/home/node/.n8n
volumes:
  postgres_data:
  n8n_data:

Key Annotations:

  • db service: This block configures the PostgreSQL container. It uses the official postgres:14 image and sets environment variables for the user, password, and database name. A named volume, postgres_data, is mounted to /var/lib/postgresql/data to ensure the database contents persist even if the container is recreated.
  • n8n service: This block defines the n8n container. The depends_on: - db directive is critical as it ensures the PostgreSQL database container is running and healthy before the n8n service attempts to start.
  • environment variables: These variables configure n8n to connect to the PostgreSQL service using the credentials defined in the db service. Additionally, N8N_BASIC_AUTH_... variables enforce a login screen for the n8n editor, a vital security measure. The N8N_HOST and WEBHOOK_TUNNEL_URL variables ensure that n8n correctly generates URLs for its webhooks and that they are publicly accessible via the designated domain.3
  • N8N_ENCRYPTION_KEY: This variable is used to encrypt sensitive credentials stored in the n8n database. If this variable is not explicitly set, n8n will generate a new key on its first launch. It is a best practice to define a key and back it up. Without a backed-up key, all encrypted credentials would be irrecoverably lost upon container recreation.
  • volumes: This section defines the named volumes that are used by the services. This is a critical practice for data persistence, ensuring that workflows, credentials, and the database remain intact across container restarts and updates.

2.3 Step 3: Bringing the Stack to Life

With the docker-compose.yml file in place, the entire stack can be launched with a single command.

Navigate to the ~/n8n directory and execute the following command:

Bash

docker compose up -d

The up command will read the docker-compose.yml file, pull the necessary Docker images, and create and start the containers. The -d flag runs the containers in “detached” mode, allowing them to run in the background.

To verify that the containers are running, use the following command:

Bash

docker ps

The output should list both the n8n and db containers with a status of Up. If a container is not running, its status will be

Exited. To troubleshoot, inspect the container logs with:

Bash

docker logs <container_name>

Part III: Securing and Hardening the n8n Stack

A functional deployment is only the first step. For a true production-ready environment, the stack must be secured against external and internal threats.

3.1 Step 4: Securing with a Reverse Proxy and SSL

This step is arguably the most critical for production deployments. It provides two distinct pathways for configuring a reverse proxy, Nginx or Traefik.

Option A: Nginx and Certbot

Nginx is a robust and widely used web server and reverse proxy. When paired with Certbot, it provides a powerful and transparent way to secure n8n with an SSL certificate from Let’s Encrypt.

  1. Install Nginx and Certbot:Bashsudo apt update sudo apt install nginx certbot python3-certbot-nginx -y
  2. Configure Nginx Reverse Proxy: Create a new Nginx configuration file for n8n.Bashsudo nano /etc/nginx/sites-available/n8n.conf Paste the following configuration, replacing n8n.yourdomain.com with the actual domain name. This configuration not only proxies traffic but also explicitly enables WebSocket support. This is a crucial detail, as n8n’s user interface relies on WebSockets for real-time updates. Without this configuration, the UI will load but display a persistent “Connection lost” error, even with a valid HTTPS connection.14Nginxserver { listen 80; server_name n8n.yourdomain.com; location / { proxy_pass http://localhost:5678; 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; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
  3. Enable and Test the Configuration:Bashsudo ln -s /etc/nginx/sites-available/n8n.conf /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl restart nginx
  4. Obtain and Install SSL Certificate with Certbot:Bashsudo certbot --nginx -d n8n.yourdomain.com --non-interactive --agree-tos -m your-email@example.com Certbot will automatically modify the Nginx configuration to enable HTTPS and manage certificate renewals.

Option B: Traefik

Traefik is an alternative that simplifies the reverse proxy and SSL setup through a declarative approach. It automatically discovers services running in Docker and configures routing and SSL certificates based on labels added to the docker-compose.yml file.

  1. Configure Traefik Service: Add a new service for Traefik and an external network to the docker-compose.yml file.9YAMLservices: traefik: image: "traefik:v2.10" container_name: "traefik" restart: unless-stopped command: - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entrypoints.web.http.redirections.entryPoint.to=websecure" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "traefik_acme:/letsencrypt" n8n: # existing n8n service labels: - "traefik.enable=true" - "traefik.http.routers.n8n.rule=Host(`n8n.yourdomain.com`)" - "traefik.http.routers.n8n.entrypoints=websecure" - "traefik.http.routers.n8n.tls.certresolver=letsencrypt" - "traefik.http.services.n8n.loadbalancer.server.port=5678" volumes: # existing volumes traefik_acme: This configuration enables Traefik to listen on ports 80 and 443, automatically detect the n8n container based on its labels, obtain a Let’s Encrypt SSL certificate, and route traffic to n8n’s internal port.9

3.2 Securing Access with Authentication

After securing the external connection with a reverse proxy, it is essential to protect the n8n application itself with an authentication layer. Basic authentication is a simple and effective method for small to medium-sized deployments.2 It is configured via environment variables within the

docker-compose.yml file.

As demonstrated in the docker-compose.yml file in Section 2.2, the following environment variables enable basic authentication:

  • N8N_BASIC_AUTH_ACTIVE=true: Activates the basic authentication feature.
  • N8N_BASIC_AUTH_USER=admin: Sets the username for the admin account.
  • N8N_BASIC_AUTH_PASSWORD=StrongPasswordHere: Sets the password.

For production deployments, it is considered a best practice to never hardcode secrets like passwords or API keys directly in a configuration file. Instead, they should be stored in a

.env file that is referenced by docker-compose or, for more advanced setups, in a dedicated secrets manager.

Part IV: Operational Management and Maintenance

A production-grade installation requires a clear strategy for ongoing maintenance, updates, and disaster recovery.

4.1 Updating the n8n Stack

Updating a Docker Compose-based n8n installation is a straightforward three-step process.1

  1. Pull the latest images: This command downloads the most recent versions of the n8n and PostgreSQL images.Bashdocker compose pull
  2. Stop and remove the existing containers: This shuts down the running services gracefully while preserving the persistent data in the named volumes.Bashdocker compose down
  3. Start the new containers: This command recreates and starts the containers with the newly pulled images.Bashdocker compose up -d

Before performing a major update, it is prudent to consult the official n8n documentation for any breaking changes that may affect the deployment.

4.2 Data Backups and Disaster Recovery

A critical distinction must be made between data persistence and data backup. The use of named Docker volumes ensures persistence, meaning the data survives container recreation. However, it does not protect against host machine failure, accidental deletion, or a compromised file system. A true disaster recovery strategy requires backing up the data off the machine.

The two essential components to back up are the n8n data volume and the PostgreSQL database.

  • n8n Data Volume (n8n_data): This volume contains the n8n user folder, which holds critical configuration data and the encryption key. The simplest method is to use a cron job to create a compressed archive of the volume and transfer it to an external location (e.g., cloud storage or another server).
  • PostgreSQL Database (postgres_data): The database stores all workflows, credentials, and execution data. The recommended method for backing up a PostgreSQL database is to use the pg_dump utility. This can be done by executing the command inside the running db container.Bashdocker exec -t n8n_db pg_dump -U n8n n8n > n8n_db_backup.sql This command creates a SQL dump of the database that can be transferred to a secure, external location.
Variable NamePurposeBest Practice Value/Recommendation
DB_TYPESpecifies the database typepostgresdb
DB_POSTGRESDB_HOSTHostname of the database servicedb (the service name in docker-compose)
DB_POSTGRESDB_DATABASEDatabase nameA strong, unique name (e.g., n8n)
DB_POSTGRESDB_USERDatabase userA strong, unique username (e.g., n8n)
DB_POSTGRESDB_PASSWORDDatabase passwordA strong, randomly generated password
N8N_ENCRYPTION_KEYKey for credential encryptionA long, randomly generated string. Back up this key!
N8N_HOSTThe host on which n8n listensn8n.yourdomain.com
WEBHOOK_TUNNEL_URLThe public URL for webhookshttps://n8n.yourdomain.com
N8N_BASIC_AUTH_ACTIVEEnables basic authtrue
N8N_BASIC_AUTH_USERUsername for basic authadmin (or another strong username)
N8N_BASIC_AUTH_PASSWORDPassword for basic authA strong, randomly generated password

Conclusion

A best-practice n8n installation on an Ubuntu Docker container is a multifaceted endeavor that extends beyond a simple docker run command. It is an architectural commitment to reliability, security, and long-term maintenance. The fundamental pillars of this architecture are:

  1. Containerization: The use of Docker Compose to encapsulate n8n and its dependencies ensures a consistent, isolated, and easily manageable environment.
  2. Robust Data Layer: Shifting from the default SQLite database to a production-grade PostgreSQL instance is essential for handling concurrent operations and preserving data integrity.
  3. Secure Access: The deployment of a reverse proxy, such as Nginx or Traefik, is not merely a security enhancement but a functional requirement for enabling HTTPS and ensuring n8n’s webhooks and UI operate correctly.
  4. Proactive Security: Implementing layered security, from basic authentication to the disciplined management of sensitive environment variables and the explicit backup of the encryption key, is a non-negotiable part of responsible hosting.

By following this comprehensive guide, an administrator can establish a foundational infrastructure that is not only functional for immediate use but also scalable, secure, and resilient for mission-critical automation tasks. The principles outlined here empower the user with the knowledge to maintain the system, troubleshoot common issues, and confidently operate n8n in a production environment.

The research for the report was based on a variety of sources. Here is a consolidated list of the references used:

  1. https://medium.com/@16priyanto/build-your-own-n8n-saas-platform-using-docker-swarm-traefik-65193b89c0ba
  2. https://docs.n8n.io/hosting/installation/docker/
  3. https://www.digitalocean.com/community/tutorials/how-to-setup-n8n
  4. https://docs.n8n.io/hosting/configuration/environment-variables/deployment/
  5. https://hub.docker.com/r/n8nio/n8n
  6. https://github.com/n8n-io/n8n-hosting/tree/main/docker-compose/withPostgres
  7. https://docs.docker.com/engine/security/rootless/
  8. https://www.thomas-krenn.com/en/wiki/Installation_of_Reverse_Proxy_for_n8n_with_Nginx_Proxy_Manager
  9. https://www.reddit.com/r/n8n/comments/1k47ats/n8n_best_practices_for_clean_profitable/
  10. https://osher.com.au/blog/guide-to-n8n-configuration-settings/
  11. https://dev.to/tahsin000/how-i-deploy-n8n-on-a-vps-with-docker-nginx-https-simple-step-by-step-2g73
  12. https://jortdevreeze.com/blog/ai-agents-6/how-to-install-n8n-with-docker-and-traefik-32
  13. https://community.n8n.io/t/self-hosted-n8n-docker-with-nginx-for-ssl/167459
  14. https://groovetechnology.com/blog/software-development/comprehensive-guide-to-n8n-installation-set-up-for-success/
  15. https://flywp.com/blog/13138/deploy-n8n-workflow-automation-with-docker-compose/
  16. https://www.youstable.com/blog/install-n8n-on-docker/
  17. https://www.youtube.com/watch?v=a_JpkazmcoI
  18. https://runcloud.io/blog/n8n-hosting-docker-nginx
  19. https://www.hostinger.com/tutorials/how-to-self-host-n8n-with-docker
  20. https://www.reddit.com/r/n8n/comments/1mfotxf/whats_your_approach_for_managing_environment/