Skip to main content
Tutorial

How to Automate VPS Management with n8n Self-Hosted (2026)

n8n self-hosted turns your VPS into a zero-cost automation engine — disk monitoring, uptime alerts, and Docker cleanup workflows, built in under an hour.

T

TUANOPS Editorial

Independent IT tool researchers

April 29, 2026 8 min read 9 sections
Affiliate disclosure: Some links earn us a small commission at no extra cost to you. Ratings are always independent.
Table of Contents (9 sections)

I've been running n8n self-hosted on my VPS for over a year. What started as a simple webhook handler evolved into the backbone of my entire ops automation stack — disk space monitoring, service uptime alerts, Docker cleanup, and backup verification all running for €0 in software cost. If you're still SSHing in manually to check `df -h` or restarting services by hand, this tutorial will fix that permanently.

Most guides on this topic use n8n to call a hosting provider's API — meaning you need a separate server for n8n and a specific cloud's API credentials. This tutorial takes the simpler, more powerful approach: n8n runs directly on the VPS you're managing. It gets direct OS access via Execute Command nodes, works on any Linux VPS (Hetzner, Vultr, Hostinger, Contabo — anything), and costs nothing extra.

Prerequisites

  • A Linux VPS running Ubuntu 22.04+ — minimum 1 GB RAM (I use Hostinger KVM 1 and Hetzner CX22 for side projects; either works)
  • Docker and Docker Compose installed on the server
  • A Telegram account — you'll create a free bot in Step 2 for instant alerts
  • Basic Linux terminal comfort — you'll run 3–4 commands total

Need a VPS? For vps for self-hosted applications in 2026, Hetzner CX22 is the best starting point — €5.99/mo for 2 vCPU, 4 GB RAM, and 20 TB monthly bandwidth.

Hetzner Cloud — Best Value · 4.9/5

Best price-per-resource for self-hosted workloads. CX22 at €5.99/mo — 2 vCPU, 4 GB RAM, 20 TB bandwidth. The go-to VPS for running n8n and side-project infrastructure.

What We're Building

One complete, production-ready workflow: a daily disk space monitor that checks your server's storage, and fires a Telegram alert the moment usage crosses 80%. You'll run through every node — Cron, Execute Command, Code, IF, and Telegram — so you understand the pattern. Once you do, adding more workflows takes 15 minutes each.

At the end, I'll show you the 3 workflows I actually run in production: uptime watchdog, Docker cleanup, and backup verification.

Step 1: Install n8n Self-Hosted with Docker

SSH into your VPS and create a working directory:

mkdir ~/n8n && cd ~/n8n

Create a docker-compose.yml file:

services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=changethis
    volumes:
      - ~/.n8n:/home/node/.n8n

Start it:

docker compose up -d

Open http://your-server-ip:5678 in your browser. n8n's UI loads immediately. For production, put Nginx or Caddy in front with SSL — but for this tutorial, direct access works fine.

This is the open-source workflow automation self-hosted approach — no monthly subscription, no execution limits, no external dependency.

n8n — Most Flexible · 4.7/5

Open-source workflow automation — self-host for free with unlimited workflows and executions. Cloud plan from €24/mo if you'd rather skip the server setup.

Step 2: Create a Telegram Bot for Alerts

Telegram's free bot API is the fastest way to wire up operational alerts. You'll have it working in under 5 minutes.

  1. Open Telegram and search for @BotFather
  2. Send /newbot and follow the prompts to name your bot
  3. Copy the API token BotFather returns — it looks like 7123456789:ABCDEFabcdef_xyz
  4. Start a conversation with your new bot (search for its username, click Start)
  5. Visit https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates in your browser
  6. Find the "id" value inside the "chat" object — that's your Chat ID

Save both the token and chat ID — you'll paste them into n8n in Step 5.

Step 3: Build the Disk Monitoring Workflow

In the n8n UI, click + New Workflow. You'll build 5 nodes connected in sequence.

Node 1 — Schedule Trigger: Search for Schedule Trigger. Set it to run Every Day at 8:00 AM. This fires the workflow every morning before your workday starts.

Node 2 — Execute Command: Add an Execute Command node. In the Command field, enter:

df / | awk 'NR==2 {print $5}' | tr -d '%'

This runs directly on the VPS and returns a single integer — the root partition's used percentage (e.g., 73). No API calls, no credentials, no network dependency.

Node 3 — Code: Add a Code node (JavaScript mode). Paste this:

const raw = $input.first().json.stdout.trim();
const diskPercent = parseInt(raw, 10);

if (isNaN(diskPercent)) {
  throw new Error('Failed to parse disk usage: ' + raw);
}

return [{ json: { diskPercent, threshold: 80, breached: diskPercent >= 80 } }];

This parses the raw output and adds a breached flag that the IF node reads next.

Step 4: Add the IF Condition and Telegram Alert

Node 4 — IF: Add an IF node. Set the condition: Value 1 = {{ $json.diskPercent }}, Operation = Greater or Equal, Value 2 = 80.

The true branch fires when disk is at or above 80%. Wire a Telegram node to it. The false branch goes nowhere — no alert when everything is healthy.

Node 5 — Telegram (true branch): Add a Telegram node. Create a new credential with your bot token. Set the Chat ID to the one from Step 2. Use this message template:

⚠️ *Disk Alert* — {{ $('Code').item.json.diskPercent }}% used

Threshold: {{ $('Code').item.json.threshold }}%
Checked: {{ $now.toISO() }}

Action: ssh user@your-vps-ip and run: du -sh /* | sort -rh | head -10

The last line tells you exactly what to run when you get the alert. Operational alerts should be actionable, not just alarming.

Step 5: Test and Activate the Workflow

Click Execute Workflow (the play button at the top). n8n runs all 5 nodes and shows the output at each step.

If disk is below 80%, the IF node routes to the false branch — nothing fires. To test the Telegram message path without filling up your disk: temporarily change the IF threshold to 10, run once, then set it back to 80.

Once tested, click Activate (top-right toggle). The workflow will now run every morning at 8:00 AM automatically.

Tips & Common Mistakes

  • Execute Command vs SSH node: Execute Command only works when n8n runs on the same server you're monitoring. If n8n is on a separate machine, use the SSH node with your server's credentials instead — same commands, different node.
  • Telegram chat ID gotcha: You must send at least one message to your bot before getUpdates returns your chat ID. If the API response is empty, message the bot first, then refresh.
  • n8n runs as non-root by default: The Docker image runs as the node user. Commands like df and free work fine without root. For commands that need elevated access, configure a minimal sudoers entry — don't run the n8n container as root.
  • Store credentials properly: Use n8n's built-in Credentials system for your Telegram token. Never hardcode tokens directly in node parameters — credentials are encrypted at rest, parameters are not.
  • Reverse proxy for production: Once you're done testing, put n8n behind Nginx or Caddy with an SSL cert. The certbot --nginx command handles Let's Encrypt in about 3 minutes.

Next Steps: 3 More Workflows I Run in Production

With the disk monitor pattern clear, these three n8n workflows for AI and general VPS ops follow the same structure and take about 15 minutes each to set up.

1. HTTP Service Uptime Watchdog

Schedule Trigger (every 5 minutes) → HTTP Request node (GET your service URL, e.g., http://localhost:3000/health) → IF Status Code not equal to 200 → Telegram alert + optional Execute Command to restart the service (docker restart container-name). This replaces a basic external uptime monitor and keeps you notified within 5 minutes of any service going down.

2. Weekly Docker Image Cleanup

Schedule Trigger (Sundays at 2:00 AM) → Execute Command: docker system prune -f 2>&1 → Telegram confirmation with the bytes reclaimed. I recovered 4+ GB in the first run on a 6-month-old server. Runs silently every week, sends one line of confirmation.

3. Backup Verification Alert

Schedule Trigger (daily, 10 minutes after your backup cron) → Execute Command: ls -lt /path/to/backups | head -5 → Code node to check if the newest file is from today → IF older than 24 hours → Telegram alert. This catches the silent backup failures that only surface during a restore. I've had this trigger twice in the past year — both times the backup script had silently broken.

All three patterns are identical to what you built: trigger → check → condition → notify. Once n8n is running on your VPS, the only limit is what bash commands can tell you — which is everything.

Done reading? Find your next tool.

Independent reviews, honest pricing — no paid placements.

Browse All Tools →

Want honest tool reviews?

TUANOPS reviews IT tools so developers and indie hackers can make smarter decisions. No paid placements. Updated monthly.