DEV Community

Cover image for Build a Local Automation Enviroment: Self-Hosted n8n + Node.js API with Docker Compose 🐳
Marce
Marce

Posted on

Build a Local Automation Enviroment: Self-Hosted n8n + Node.js API with Docker Compose 🐳

When it comes to workflow automation, n8n is one of the most powerful open-source tools avalible. However, relying exclusively on third-party APIs or cloud instances can introduce latency, strict rate limits, and data privacy concerns.

The solution? A self-hosted, cloud-native architecture.

In this tutorial, I will Show you how to spin up a local development environment that orchestrates an n8n container and a custom Node.js REST API, communicating securely through an internal Docker bridge network.

The Architecture

Instead of exposing aour database or API to the public internet for n8n to consume, we will encapsulate both services within a Docker bridge network.

This provides two main benefits:

  1. Security: Services can communicate with each other internally, but you maintain full control over which ports are exposed to the host machine.
  2. POrtability: You can take this exact boilerplate and deploy it to a VPS (like Civo, DigitalOcean, or AWS) in seconds.

Step 1: Building the Node.js API

First, we need a backend service for n8n to interact with. We will use Express for its simplicity.
In the project root, create a subdirectory called API with an index.js file:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

//Endpoint de prueba que n8n va a consumir
app.get('/API/data', (req, res) => {
    res.json({
        success: true,
        message: "Hi from your API!",
        data: {
            id: 1,
            status: "active",
            timestamp: new Date()
        }
    });
} );

app.listen(PORT, () => {
    console.log('API de NODE.js running on port ${PORT}');
});

Enter fullscreen mode Exit fullscreen mode

To containerize this, we add a lightweight Dockerfile based on the Node Alpine image:

# Usar una imagen oficial y ligera de Node.js
FROM node:18-alpine

#Crear y establecer el directotrio de trabajo dentro del contenedor
WORKDIR /usrc/app

#Copiar los archivos de dependencias
COPY package*.json ./

#Copiar el resto de código de la API
COPY . .

#Exponer el puerto que una la API
EXPOSE 3000

#Comando para iniciar la aplicación
CMD ["node", "index.js"]

Enter fullscreen mode Exit fullscreen mode

Step 2: The Docker Compose Magic

This is where everything como together. In the root of our project, we create our docker-compose.yml file. This acts as the blueprint for our infraestructure.

services:
 my-api-node:
  build: ./API
  container_name: api_nodejs
  ports:
    - "3000:3000"
  networks:
    - n8n-network
  restart: unless-stopped

 n8n:
  image: docker.n8n.io/n8nio/n8n
  container_name: n8n_autoalojado
  ports:
    - "5678:5678"
  environment:
    - N8N_HOST=localhost
    - N8N_PORT=5678
    - N8N_PROTOCOL=http
    - NODE_ENV=production
    - WEBHOOK_URL=http://localhost:5678/
    - GENERIC_TIMEZONE=America/Argentina/Buenos_Aires
  volumes:
    - n8n_data:/home/node/.n8n
  networks:
    - n8n-network
  restart: unless-stopped
  depends_on:
    - my-api-node

networks:
  n8n-network:
    driver: bridge

volumes:
  n8n_data:

Enter fullscreen mode Exit fullscreen mode

Key takeaways from this configuration:

  • Shared Network: Both services are tied to n8n-network. Inside n8n, instead of calling localhost:3000, we can make HTTP requests directly to https://api_nodejs:3000. Docker handles the DNS resolution automatically.

  • Data Persistence: The n8n_data volume ensures thet even if you tear down the container, your workflows remain safely stored on your local machine.

Step 3: Spin Up the Environment

With Docker running on your machine, open your terminal in the project root and execute:

docker compose up -d --build

Enter fullscreen mode Exit fullscreen mode

The -d (detached) flag runs the services in the background, while the --build flag ensures our custom Node.js image is compiled with the latest changes.

That's it!

Conclusion

Setting up a local containerized environment saves you from dealing with cross-platform configuration issues, broken global dependencies, and Node.js version conflicts.

You can check out the complete source code for this boilerplate on my GitHub Repository: https://github.com/WhoIsMarce/proyecto-n8n-nodejs.git

Have you used n8n with local APIs before? Let me know in the comments what kind of automations you would build with this setup!

I'm Marcela Zapata Vanegas. Technical Writer & Full Stack Developer. I am passionate about simplifying cloud architecture and automating workflows.

Top comments (0)