İçeriğe Atla
Mustafa Erbay
Tutorials · 11 min read · görüntülenme Türkçe oku
100%

Build Your Own AI Automation with n8n: Self-Hosted, No-Code Agent

Sharing my experience building self-hosted AI automations using n8n. Creating no-code agent flows, RAG, and multi-LLM integration steps.

n8n interface on a computer screen with AI symbols, representing self-hosted AI automation.

Automating workflows has always been a priority for me, especially for repetitive and error-prone manual processes. Recently, integrating AI capabilities into these automations offers a great opportunity for those, like me, who seek practical solutions. However, this integration often requires coding or complex API integrations. This is where “low-code/no-code” tools like n8n come into play. I used n8n to set up AI-powered agent flows on my own servers, without compromising data privacy and control. In this post, I will share my experience and explain how to do it step-by-step.

Why n8n and Self-Hosted AI Automation?

A few years ago, I experimented with different automation tools, especially for simple data transfers and notification flows. But when AI capabilities became involved, I either found them too expensive or avoided cloud-based solutions due to data security concerns. Especially in a client project where we needed to set up an automation handling sensitive financial data, a self-hosted solution became inevitable. n8n offers a wide range of integrations and, thanks to Docker support, I can easily host it on my own server.

For me, self-hosting is not just about cost advantage; it also means having complete control over my data. Especially when using AI agents, the question of how much of the data you send to LLMs is logged or used for training is always a concern. With an n8n setup under my control, I minimized these worries. Moreover, n8n’s flexible structure gives me the freedom to add as many custom integrations or LLM providers as I want. This is a significant advantage for someone like me who enjoys testing different LLMs.

Setup Steps: Quick Start with Docker Compose

The easiest way to run n8n on your own server is by using Docker Compose. I usually write the docker-compose.yml file myself for simple setups. This gives me flexibility and makes debugging easier in case of potential issues. The example below will be sufficient for a basic n8n setup. Here, I’m using PostgreSQL as the database because n8n working with SQLite can lead to issues like WAL bloat, especially under high load or unexpected shutdowns. I also added Redis for caching and queueing, which improves performance.

First, create a directory on your server and place the docker-compose.yml file inside it:

mkdir n8n-ai-automation
cd n8n-ai-automation
nano docker-compose.yml

The docker-compose.yml content might look like this:

version: '3.8'

services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=${N8N_HOST:-localhost}
      - N8N_PORT=5678
      - N8N_PROTOCOL=${N8N_PROTOCOL:-http}
      - WEBHOOK_URL=${WEBHOOK_URL:-http://localhost:5678/}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB:-n8n}
      - DB_POSTGRESDB_USER=${POSTGRES_USER:-n8n}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD:-n8n}
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=${N8N_USER:-admin}
      - N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD:-admin_password_change_me}
      - QUEUE_BULL_REDIS_HOST=redis
      - QUEUE_BULL_REDIS_PORT=6379
      - N8N_METRICS_ENABLED=true # For monitoring metrics with tools like Prometheus
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - postgres
      - redis
    # Resource limits are important to protect against OOM killer
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G

  postgres:
    image: postgres:15
    restart: always
    environment:
      - POSTGRES_DB=${POSTGRES_DB:-n8n}
      - POSTGRES_USER=${POSTGRES_USER:-n8n}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-n8n}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    deploy:
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

  redis:
    image: redis:7
    restart: always
    volumes:
      - redis_data:/data
    deploy:
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 128M

volumes:
  n8n_data:
  postgres_data:
  redis_data:

This file defines the n8n, PostgreSQL, and Redis services. I configure n8n’s database connection information and basic authentication settings using environment variables. Don’t forget to use N8N_BASIC_AUTH_ACTIVE and the user/password variables for security. Additionally, I specified the amount of memory to be allocated to each service with limits and reservations under deploy.resources. This is critical, especially in VPS environments, to prevent excessive resource consumption and OOM-killed errors. Last month, I saw a build container for one of my side products get OOM-killed due to a sleep 360 command in its CI/CD pipeline, so defining resource limits from the start has become a habit.

After saving the file, you can start the services with the docker compose up -d command:

docker compose up -d

Within a few minutes, you can access the n8n interface at http://localhost:5678. If you are using a reverse proxy (like Nginx), you will need to adjust the N8N_HOST and N8N_PROTOCOL variables accordingly. I usually set up SSL termination with Nginx and publish n8n under an address like https://automations.mysite.com.

Creating Your First AI Agent Flow

n8n’s power comes from its ability to create complex workflows through a visual interface without writing code. We can set up our first AI agent flow using a scenario where an incoming email is summarized and a notification is sent to Slack. This was a simple but effective method I used in a client project to quickly triage support emails.

  1. Trigger: To start the workflow, we can use an “Email” trigger. I usually set up a “Webhook” trigger and route emails from another service (e.g., Mailgun or a simple email parser I wrote) to this webhook. However, n8n also has its own “IMAP Email” or “Gmail” nodes. For simplicity, let’s start with a “Manual Trigger” and then connect it to a real trigger later.

  2. LLM Node: Under the “AI” category, you will find many LLM (Large Language Model) nodes. I usually use “OpenAI” or “Generic LLM” nodes. The “Generic LLM” node provides access to different LLMs via OpenRouter or your own custom APIs. Drag and drop this node onto the canvas.

  3. Prompt Engineering: Inside the LLM node, we will enter a System Prompt and User Prompt to instruct it to summarize the email. Prompt engineering is critical here. While using AI for production planning in a manufacturing company’s ERP, I repeatedly tested how detailed and guiding the prompts needed to be.

    System Prompt example:

    You are an AI assistant that summarizes incoming customer support emails.
    Focus on the main issue, the customer's name (if available), and any urgent requests.
    Keep the summary concise, maximum 3 sentences.

    User Prompt example:

    Summarize the following email:
    ---
    Subject: About the Defective Product
    From: Ayşe Yılmaz <[email protected]>
    Date: 2026-06-15
    Body: Hello, the X brand product I purchased with order number 12345 turned out to be defective. I have been using it for a week, and it suddenly stopped working yesterday. I urgently request a replacement. Please contact me as soon as possible. Thank you, Ayşe Yılmaz.
    ---

    You can dynamically link the content of the incoming email to this example using expressions like {{ $json.body.text }}.

  4. Slack Node: Add a “Slack” node to send the summary from the LLM to a Slack channel. When configuring the Slack node, you will need to provide a Webhook URL or Bot Token. You can link the output from the LLM node to the message part using {{ $node["LLM Node"].json["text"] }}.

After creating this flow, you can check if it works by clicking the “Test Workflow” button or by triggering a test email. As you can see, we have set up an AI-powered automation with a few drag-and-drop operations, without writing any code.

Real-World Agent Flows: RAG and Multi-LLM Integration

In more complex scenarios, our AI agents need access not only to general knowledge but also to our specific datasets. This is where RAG (Retrieval-Augmented Generation) comes in. In a client project, while building a knowledge base for a bank’s internal platform, I used a RAG architecture to ensure LLMs had access to accurate and up-to-date information. We can do this with n8n without writing any code.

RAG Integration

The basic idea for RAG is to retrieve the most relevant information from our own data sources before asking the LLM a question, and then adding this information to the prompt.

  1. Data Source: Your internal documents (PDFs, text files, database records) should be embedded in a vector database (e.g., Pinecone, Weaviate, Qdrant, or even PostgreSQL’s pg_vector extension). n8n has direct integration nodes for these vector databases. On my end, I usually prefer PostgreSQL with pg_vector because using a technology I already have eliminates additional costs.

  2. Generating Embeddings: Before uploading your documents to the vector database, you need to create their “embeddings” (numerical vector representations). You can use nodes like “OpenAI Embeddings” or “Cohere Embeddings” for this.

  3. Vector Search: When a question comes in (e.g., from a Webhook trigger), you search for the most relevant document chunks related to the question using the appropriate vector database node from the “Vector Store” category.

  4. Enriching the Prompt: You enrich the prompt by adding the information from the search results (usually text snippets) to the LLM node’s User Prompt. For example:

    Here is some relevant information from our internal knowledge base:
    ---
    {{ $node["Vector Search"].json["results"] }}
    ---
    Based on the information above, answer the following question:
    {{ $json.query }}

This way, the LLM can generate more accurate and contextual answers by being fed not only general information but also your corporate knowledge.

Multi-LLM Provider Integration and Fallback

Relying on a single LLM provider can be risky in terms of both cost and performance. Different providers offer different models, and the costs, speeds, and performances of these models vary. With n8n, I can integrate multiple LLM providers and set up fallback mechanisms to switch to another provider based on the situation or if one provider fails. I typically use providers like Groq, Gemini Flash, and OpenRouter together. Groq stands out for its speed, Gemini Flash might be more affordable, and OpenRouter offers various models through a single API.

Example of a multi-LLM flow:

  1. Main LLM Attempt: First, I use my primary preferred LLM provider (e.g., Groq).
  2. Error Checking: If an error occurs from the Groq node (e.g., API timeout or rate limit), I check this condition with an “IF” node.
  3. Fallback LLM: In case of an error, I switch to another LLM node (e.g., Gemini Flash via OpenRouter) from the “true” branch of the “IF” node.
  4. Result Merging: I can then merge the results from both LLMs with a “Merge” node and present them as a single output to the rest of the flow.

This architecture is vital for ensuring continuity, especially in critical workflows. I use this fallback mechanism in the AI-based predictions for financial calculators in one of my side products. This way, if there’s an issue with one provider, the user experience isn’t interrupted.

Operational Details: Security, Monitoring, and Maintenance

Setting up a self-hosted system brings with it operational responsibilities. I take some basic precautions to ensure n8n runs smoothly and securely.

Security Measures

  • Nginx Reverse Proxy and SSL: Instead of exposing n8n directly to the internet, I place an Nginx reverse proxy in front of it. With Nginx, I perform SSL termination (free with Let’s Encrypt) and add basic security layers. For example, I use rate limiting to create the first line of defense against DDoS attacks. I also set HTTP security headers like X-Content-Type-Options and X-Frame-Options.

    Example Nginx configuration:

    server {
        listen 80;
        server_name automations.mysite.com;
        return 301 https://$host$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name automations.mysite.com;
    
        ssl_certificate /etc/letsencrypt/live/automations.mysite.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/automations.mysite.com/privkey.pem;
    
        # Security headers
        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-Content-Type-Options "nosniff";
        add_header X-XSS-Protection "1; mode=block";
    
        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;
            # Rate limiting example
            # limit_req zone=one burst=5 nodelay;
        }
    }
  • Fail2ban: I use fail2ban to prevent brute-force attacks on my server via SSH. I can also track failed login attempts to n8n’s web interface from logs and block them with fail2ban. For this, I centralize n8n logs with journald and write a custom jail rule for fail2ban.

    Example fail2ban jail rule (for n8n):

    [n8n-auth]
    enabled = true
    port = http,https
    filter = n8n-auth
    logpath = /var/log/syslog # Or where logs from journald are stored
    maxretry = 5
    bantime = 3600

    And filter.d/n8n-auth.conf file:

    [Definition]
    failregex = .*n8n.*authentication failed for user.*<HOST>.*
    ignoreregex =

    This rule detects failed login attempts by searching for the “authentication failed for user” pattern in n8n logs and blocks the IP address for one hour.

  • Kernel Module Blacklist: To protect against security vulnerabilities, I blacklist kernel modules I don’t use. Taking such precautions is especially important when modules like algif_aead have old CVEs (like CVE-2026-31431). This improves overall system security.

Monitoring and Maintenance

  • Log Management: I centralize all Docker container logs with journald. This is crucial for troubleshooting and security auditing. In case of an error, I monitor live logs with journalctl -u docker.service -f or check past logs with journalctl -u docker.service --since "1 hour ago".
  • Resource Monitoring: I keep memory and CPU usage under control by specifying cgroup limits in the Docker Compose file. Additionally, I monitor n8n’s own metrics (enabled with N8N_METRICS_ENABLED=true) and the server’s overall resource usage with tools like Prometheus and Grafana. I particularly track database and cache server metrics to detect issues like PostgreSQL WAL bloat or Redis OOM eviction policy proactively.
  • Backup: I take regular backups for the PostgreSQL database. I automate this process with the pg_dump command or a backup tool. n8n workflows can also be exported as a JSON file, which helps in recovery scenarios.

Conclusion and Next Steps

Setting up my own AI automations self-hosted with n8n has provided me with both flexibility and cost advantages. The ability to create complex agent flows without writing code, use my own data with RAG, and integrate different LLM providers is a huge plus. I use these types of AI automations in many different scenarios, such as production planning in a manufacturing ERP, prioritizing customer support emails on an e-commerce site, or making financial predictions in my own side product.

This setup was a project that brought together my experience in many areas, not just AI integration, but also system administration, network security (Nginx, fail2ban), and database optimization (PostgreSQL). Although I initially encountered insidious issues like MTU/MSS mismatches or DNS negative caching, I debugged and resolved them step-by-step.

If you also want to build your own AI automations but don’t want to write code and data control is a priority for you, a self-hosted n8n setup is definitely worth trying. As a next step, I’m exploring how to use “agent patterns” (planning, tool use, memory) more effectively within n8n to make these AI agents even smarter. Perhaps I’ll cover this topic in my next post.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Comments

Server-side AI Moderation

Comments are AI-moderated server-side and stored permanently.

?
0/2000

Server-side AI moderation

✉️ Free · No spam · Unsubscribe anytime

Curated digest, hand-picked by me — not the AI

Once a week: the most important post of the week, behind-the-scenes notes, and a "what I actually used this week" section. Less noise, more signal.

  • 📌
    Best of the week Single most-worth-reading post
  • 🔧
    Toolbox notes Real tools I used this week
  • 🧠
    Behind-the-scenes Notes that don't make it to blog

We don't spam. Unsubscribe anytime. · Tracked only by Umami (self-hosted, no Google).

Your Reading Stats

0

Posts Read

0m

Reading Time

0

Day Streak

-

Favorite Category

Related Posts