Skip to content
Home » All Posts » How to Prepare Self-Hosted n8n with Docker and Your Own Domain

How to Prepare Self-Hosted n8n with Docker and Your Own Domain

Introduction

If you’re the kind of developer or IT tinkerer who likes to have things under your own control, running self-hosted n8n on your own machine is a fantastic option. Instead of relying on someone else’s cloud, you can spin up a local instance, secure it with HTTPS, and point a clean subdomain to it — all while keeping your workflows and data private.

This setup is especially great if you’re comfortable with a bit of hands-on work. You’ll need some basic familiarity with Dockerdomain namesport forwarding, and SSL certificates to, but nothing too overwhelming. Once you understand the flow, it’s actually a pretty smooth process.

The best part? Running n8n locally is free. You’ll only need to pay for your domain name (if you don’t already own one). In this guide, we’ll walk through creating a subdomain, pointing it to your local host, generating a trusted SSL certificate with Let’s Encrypt, and configuring self-hosted n8n to serve securely over HTTPS.

By the end, you’ll have your very own developer-grade automation platform running at something like n8n.yourdomain.com — ready to handle webhooks and workflows just like a cloud service, but with full ownership and zero monthly hosting bills.

Prerequisites

Before we roll up our sleeves and start spinning up containers, let’s make sure you have a few basics covered. This setup isn’t plug-and-play for absolute beginners — it’s aimed at folks who have a little bit of developer or IT background. You don’t need to be a DevOps wizard, but some familiarity will make the process a whole lot smoother.

Here’s what you’ll need to have ready:

  • A domain name — This is the only thing that may cost you a bit of money. You’ll use it to create a subdomain like n8n.yourdomain.com so your local instance can be reached via domain name from anywhere. You can get one from godaddy.com.
  • Access to your DNS provider — You should have this access with the domain named purchased , so you can add or edit DNS records (A or CNAME) for your subdomain.
  • A Linux machine to run self-hosted n8n (preferred). Ubuntu 24.04 would do just fine.
  • Docker and Docker Compose installed on your machine — n8n runs beautifully in a container, and Docker makes it easy to keep things clean and isolated.Refer to here to get it installed.
  • A server or local machine (Linux like Ubuntu will do) with:
  • Access to your home modem/router – to configure port forwarding and firewall rules
  • A basic understanding of SSL/TLS certificates — nothing too deep, just enough to know what they are and where they go.
  • A bit of comfort using the command line.

If you can check off that list, you’re in a great spot. The rest of this guide will walk you through each step, from creating a subdomain to seeing your very own secure n8n instance live on the web.

Create a Subdomain for Self-Hosted n8n

First things first — we need a place on the internet to point to your local n8n instance. The cleanest way to do that is by creating a subdomain like n8n.yourdomain.com. Think of it as giving your local server its own front door on the web.

<<Please note>> You need to have already purchased a domain name from a DNS provider such as godaddy.com prior to creating a subdomain for n8n. This is one of the prerequisites above.

Log in to your DNS provider

 This is where you manage your domain name.
This could be Cloudflare, GoDaddy, Namecheap, or wherever your domain lives.

Create a new DNS record.

  • Type: A
  • Name: n8n (or whatever you want your subdomain to be)
  • Value: your server’s public IP address (or the IP of the machine where n8n will run)
  • TTL: you can leave the default or set something like 3600 seconds.

Save your changes and give DNS a bit of time to propagate.

If your machine is behind a home router, make sure you’ve set up port forwarding for ports 80 (HTTP) and 443 (HTTPS) to your local machine. This step is crucial for receiving traffic from the outside world — and for Let’s Encrypt to issue a valid SSL certificate.

If you are unsure of your public IP, you can simply Google “What is my IP“, and you it should see an IPv4 address that is accessible publicly. This is the address you will use in creating a new DNS record above.

<<Important>> If your machine is behind a home router, your modem’s public IP address may change if it reboots. If that is the case, you will need a dynamic DNC service to update this IP address automatically when it changes. This is out of the scope of this guide. Please keep that in mind!

By the end of this step, your subdomain should be pointing straight to your server. Nothing fancy will show up yet — but that’s exactly what we’ll fix in the next steps. 

Run Self Hosted n8n with Docker (Using a Dedicated Volume)

Let’s set up n8n in a way that keeps your data safe, clean, and easy to manage. Instead of mounting a folder from your host machine, we’ll create a named Docker volume just for n8n.

This gives your workflows, credentials, and settings a nice, isolated home — and makes future upgrades much smoother.

Create a dedicated Docker volume

docker volume create n8n_data 

This creates a persistent storage volume that lives outside the container’s lifecycle.

Run n8n with the named volume attached

docker run -it --rm                 \ 
        --name n8n                  \
        -p 5678:5678                \
        -v n8n_data:/home/node/.n8n \
        docker.n8n.io/n8nio/n8n 

Here’s what’s happening:

  • -p 5678:5678 exposes n8n on port 5678.
  • -v n8n_data:/home/node/.n8n mounts the named volume so your data survives container restarts.
  • --rm cleans up the container when you stop it (but not the volume).
  • --name n8n gives the container a nice, easy-to-reference name.
  • docker.n8n.io/n8nio/n8n is the official n8n image from the n8n Docker registry.

Check if n8n is running

docker ps

then open your favorite browser and navigate to this URL:

http://localhost:5678

If all goes well, you’ll see the n8n UI up and running 

Optional: You can stop or restart the container anytime with:

docker stop n8n
# or
docker restart n8n

or redeploy with different parameters to the original run command — your workflows and credentials will still be there because they live in the n8n_data volume.

Next, we’ll add a secure front door to your instance with HTTPS by grabbing a free SSL certificate from Let’s Encrypt.

Get an SSL Certificate with Let’s Encrypt

Right now, your self-hosted n8n instance is running locally over plain HTTP. That’s fine for testing on your own machine — but once you want to expose it to the internet, you really need HTTPS.

Why? Because many third-party APIs — including Google and Telegram Messenger LLP — will reject any webhook or callback to an unsecured endpoint. They only communicate with trusted and valid HTTPS URLs backed by a recognized Certificate Authority. Using Let’s Encrypt is a quick and free way to get that trust without buying a commercial certificate.

Here’s how to set it up 

Install Certbot

Certbot is the easiest way to get and manage Let’s Encrypt certificates.

On Ubuntu or Debian:

sudo apt update
sudo apt install certbot

If you’re on a different OS, check the official Certbot instructions for your environment.

Make sure ports 80 and 443 are open

Let’s Encrypt needs to verify your subdomain by connecting to your server.

  • On a home network, port forward ports 80 and 443 to your machine. This requires you to login to your modem and find the port forwarding setting. Consult your modem’s manual on how to add a port-forwarding rule.
    • You need to find out the local IP address of machine that will host n8n, on Ubuntu, you can find it out with ifconfig command.
    • You should set a static lease for this machine so your modem always leases the same IP address to it
    • and then you will add port forward rules for ports 80 and 443 to this machine.
  • A Linux machine like Ubuntu comes with a firewall, so let’s make sure the ports are allowed:
sudo ufw allow 80
sudo ufw allow 443

This step is critical — if Let’s Encrypt can’t reach your server, it can’t issue the certificate.

Request the SSL certificate

Run Certbot in standalone mode

sudo certbot certonly --standalone -d n8n.yourdomain.com

Replace n8n.yourdomain.com with your real subdomain.

If everything checks out, you’ll get a valid certificate issued by Let’s Encrypt, stored by default in:

/etc/letsencrypt/live/n8n.yourdomain.com/

The important files are:

  • fullchain.pem — your certificate + CA chain
  • privkey.pem — your private key

Verify your files

Check your cert directory:

sudo ls -l /etc/letsencrypt/live/n8n.yourdomain.com/

You should see:

cert.pem  chain.pem  fullchain.pem  privkey.pem  README

These files are what we’ll mount into the Docker container to enable HTTPS.

<<Please Note>> Let’s Encrypt certificates expire every 90 days. We’ll set up automatic renewal later so you don’t have to worry about it.

By the end of this step, you have a valid and trusted SSL certificate that will make your n8n subdomain behave like any other secure production service — ready to receive API calls from the outside world.

Configure n8n with HTTPS

You’ve got your shiny new SSL certificate from Let’s Encrypt — now let’s actually use it to make self-hosted n8n accessible over a secure, trusted HTTPS connection.

This step is important not just for encryption, but also for trust:
Platforms like Google and Telegram Messenger LLP will flat-out reject webhooks that don’t use a valid, trusted HTTPS endpoint. Self-signed certs won’t work here.

We’ll configure n8n to serve HTTPS traffic directly using the certificate and private key you just generated.

Stop any running n8n container

If you still have the previous container running, stop it first:

docker stop n8n

This will cleanly shut it down (since we used --rm, it’ll also remove the container but keep your data in the n8n_datavolume).

Mount the certificate and key

Your certs should be at:

/etc/letsencrypt/live/n8n.yourdomain.com/

These files are:

  • owned by root
  • locked down with strict permission
  • not directly readable inside a docker container

So instead of mounting them directly, it’s a better (and safer) practice to make a copy of the certificate and private key into a dedicated folder with proper permissions for n8n.

First, create a folder to store the copied certs:

sudo mkdir -p /opt/n8n/certs

Then copy the certificate and key:

sudo cp /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem /opt/n8n/certs/server.crt
sudo cp /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem /opt/n8n/certs/server.key

Next, set the correct permissions:

sudo chown root:docker /opt/n8n/certs/server.*
sudo chmod 640 /opt/n8n/certs/server.*

What this does:

  • Keeps the original Let’s Encrypt files secure
  • Ensures the n8n container can read the cert and key
  • Reduces the chance of accidental permission errors during container startup

Finally, mount the copied certs into your n8n container:

docker run -d \
  --name n8n \
  -p 443:5678 \
  -v n8n_data:/home/node/.n8n \
  -v /opt/n8n/certs/server.crt:/certs/server.crt:ro \
  -v /opt/n8n/certs/server.key:/certs/server.key:ro \
  -e N8N_PROTOCOL=https \
  -e N8N_HOST=n8n.yourdomain.com \
  -e WEBHOOK_URL=https://n8n.yourdomain.com \
  -e SSL_CERT=/certs/server.crt \
  -e SSL_KEY=/certs/server.key \
  docker.n8n.io/n8nio/n8n

Here’s what’s new:

  • -p 443:5678 means any incoming traffic on port 443 on your machine will be routed to port 5678 inside the docker container.
  • -v ...server.crt and -v ...server.key mount your SSL cert and key.
  • -e N8N_PROTOCOL=https tells n8n to serve HTTPS.
  • -e N8N_HOST sets the hostname (important for generating correct webhook URLs in n8n).
  • -e SSL_CERT and SSL_KEY point n8n to your cert files.

Visit your secure subdomain

Open your browser and head to:

https://n8n.yourdomain.com

If everything’s set up correctly, you should see a valid HTTPS connection with the green padlock (or equivalent).
You can also verify with:

curl -I https://n8n.yourdomain.com

You should get a 200 OK response with no SSL errors.

At this point, your self hosted n8n instance is:

  • Running locally in Docker 
  • Accessible through a clean subdomain 
  • Protected by a trusted HTTPS certificate 

If not, review the steps above, or send me a message so I could help you out.

Next up, we’ll make sure your certs stay fresh and don’t expire by setting up automatic renewal.

Set Up Automatic SSL Renewal

Right now your n8n instance is secured with a valid HTTPS certificate from Let’s Encrypt, but Let’s Encrypt certificates expire every 90 days.

If you don’t renew them, your nice shiny green padlock will suddenly turn into a scary browser warning and external services like Google or Telegram Messenger LLP will stop sending webhooks to your instance.

Check that Certbot is already installed

We installed Certbot earlier, but let’s double-check it’s available:

certbot --version

If you get a version number, you’re good to go. If not, just reinstall it:

sudo apt update
sudo apt install certbot

Run a renewal Test

Before automating anything, make sure renewal works cleanly:

sudo certbot renew --dry-run

This simulates the renewal process without making any real changes. If it says “Congratulations, all renewals succeeded,” you’re good to move on. If it fails, double-check the following:

  • That ports 80 and 443 are open
  • DNS is resolving correctly for your subdomain
  • Your server can reach Let’s Encrypt’s servers

Set up Cron Job for Auto Renewal

Let’s Encrypt recommends renewing about every 60 days. On most systems, Certbot already sets up a daily systemd timer, but you can also add your own cron job for extra assurance.

Open cron editor

sudo crontab -e

And add

0 3 * * * certbot renew --quiet && cp /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem /opt/n8n/certs/server.crt && cp /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem /opt/n8n/certs/server.key && chown root:docker /opt/n8n/certs/server.* && chmod 640 /opt/n8n/certs/server.* && docker restart n8n

Here’s what it does:

  • Runs at 3:00 AM every day
  • Silently renews the certificate if needed
  • Copy the certificate and the key files to /opt/n8n/certs
  • Update the permissions
  • Restart the n9n container so it picks up the new certificate

The much better way is to move the commands to a dedicated bash script and have the cron call the script instead. I will leave that to you. 😀

Access n8n Securely and Publicly

With everything setup, your self-hosted n8n should be accessible via your sub domain via https, you can now go ahead and register a new account and get started with creating your own AI agent!

n8n login
self-hosted n8n

Summary

Running n8n on your own machine gives you full controlzero hosting cost, and the ability to build powerful automations under your own domain. Here’s what we covered:

  1. Set Up Your Environment
    • Make sure you own a domain name and can configure DNS.
    • Prepare basic tools: Docker, port forwarding, and SSL knowledge.
  2. Use a Subdomain for n8n
  3. Deploy n8n in Docker with Persistent Storage
    • Create a dedicated volume using:docker volume create n8n_data
    • Run the container with mounted storage so your workflows survive restarts.
  4. Secure with HTTPS Certificates
    • Use Let’s Encrypt to issue free SSL certificates.
    • Make a safe copy of fullchain.pem and privkey.pem into /opt/n8n/certs.
    • Set proper permissions and mount these files into the container.
  5. Configure Firewall & Port Forwarding
    • Open and forward ports 80 and 443 to your server to allow certificate issuance and secure traffic.
  6. Automate Certificate Renewal
    • Schedule certbot renew with a cron job.
    • Use a simple shell script to copy the new certs, fix permissions, and restart the n8n container.
    • This ensures your site stays valid and trusted.
  7. Why HTTPS Is Crucial
    • APIs like Google, Telegram Messenger LLP, Slack, and Stripe require trusted HTTPS endpoints.
    • Without a valid cert, webhooks will fail.
  8. Ready to Build!

Join the conversation

Your email address will not be published. Required fields are marked *