1 Get the server (one-click n8n)
1.1 Get the VPS
- Hostinger → Services → VPS → self-hosted n8n landing page.
- Plan: KVM 2 — 2 vCPU / 8 GB RAM / 100 GB NVMe on AMD EPYC. More than enough for this guide, with room to upgrade.
- Pick the 24-month term (lowest monthly price) → add to cart.
- Apply coupon
RAHULWAGHat checkout — watch the price drop.
1.2 Deploy n8n (one-click)
- VPS dashboard → Setup → choose the server location nearest you.
- On the application step select the n8n template — not plain Ubuntu. If two n8n entries appear, pick the Docker-based one.
- Optional features: Malware scanner (free — take it). Docker manager is optional.
- Set a strong root password — store it in a password manager, you'll SSH later.
- Finish setup → ~5–10 min → status Running + your server IP.
n8n-xxxx and traefik. Traefik is the reverse proxy that auto-provisions HTTPS — SSL is handled out of the box.1.3 First login
- VPS page → Manage App → n8n opens at
https://n8n-xxxx.srvXXXXXXX.hstgr.cloud(already HTTPS ✅). - Create the n8n owner account (local to this server, not an n8n.io account).
- Claim the free license key: n8n emails it → Settings → Usage & plan → Enter activation key.
Verify SSH access while you're here
ssh root@YOUR_SERVER_IP
2 Your first workflow: the 7 AM digest (W2)
What we're building: a workflow that wakes up at 7 AM, reads your unread Gmail, has AI sort it by urgency, and sends the digest to your Telegram — every day, without you.
2.1 Prerequisites (10 min, one-time)
A. Telegram bot — the assistant's mouth
- In Telegram, search @BotFather (blue verified check) → send
/newbot. - Display name: Jarvis → username: anything ending in
bot(e.g.JarvisByRahul_bot). - Copy the HTTP API token it replies with — treat it like a password.
- In n8n: Overview → Credentials → Add credential → Telegram API → paste the token → Save → "Connection tested" ✅.
- Get your own chat id: press Start on your bot and send it any message, then open
https://api.telegram.org/bot<TOKEN>/getUpdatesin your browser → find"chat":{"id":123456789,...}— that number is your chat id.
B. Google OAuth — n8n's permission to read your mail
- In n8n: Overview → Credentials → Add credential → Gmail OAuth2 API → copy the OAuth Redirect URL shown at the top (keep this dialog open).
console.cloud.google.com→ create/select a project → search Gmail API → Enable.- Google Auth Platform → Clients → Create Client → Application type: Web application → name it n8n → under Authorized redirect URIs click + Add URI → paste the redirect URL → Create (leave "JavaScript origins" empty).
- Copy the Client ID and Client Secret from the popup → paste both into the open n8n dialog → Sign in with Google.
2.2 Create the workflow + Schedule Trigger
- Overview → Workflows → Create workflow (orange, top right) — a blank canvas opens.
- Click the workflow name ("My workflow") top-left → rename to W2 - Morning Digest.
- Click the big "Add first step…" square → panel: "What triggers this workflow?" → choose On a schedule.
- In node settings: Trigger Interval Days · Days Between Triggers 1 · Trigger at Hour 7am · Trigger at Minute 0.
- Click the dark canvas to close the node — you'll see your first node with a small clock icon.
2.3 Node 2 — Gmail: get the unread mail
- Click the small + on the right edge of the Schedule node → search panel opens ("What happens next?").
- Type
gmail→ pick Gmail → under Message Actions choose Get many messages. - Settings:
- Credential: your Gmail account from 2.1 is pre-selected.
- Resource: Message · Operation: Get Many.
- Return All: OFF · Limit: 30.
- Simplify: ON.
- Under Filters → Add Filter → Read Status → Unread emails only.
- Click Execute step → the OUTPUT panel fills with your real unread emails. If you see them — Gmail is wired. 🎉
2.4 Node 3 — Aggregate: 30 emails → 1 item
Why: n8n runs the NEXT node once per item. 30 emails would mean 30 separate AI calls. Aggregate merges them into one item first → one AI call.
- + after the Gmail node → search
aggregate→ pick Aggregate. - Settings:
- Aggregate: All Item Data (Into a Single List).
- Put Output in Field:
data. - Include: change All Fields → Specified Fields.
- Fields To Include:
From, Subject, snippet, labels.
- 💰 The AI only needs sender/subject/preview — this cuts tokens roughly 80%.
- Execute step → OUTPUT shows 1 item containing a
dataarray of slim emails.
2.5 Node 4 — the AI brain (Basic LLM Chain)
- + after Aggregate → search
basic llm→ pick Basic LLM Chain (Chain, not AI Agent — no tools or decisions needed, so it's cheaper and faster). - Click the + under "Model" → choose OpenAI Chat Model.
- Credential → Create new → paste your OpenAI API key (
platform.openai.com→ API keys; add billing credits first — separate from ChatGPT Plus) → Save. - Model: gpt-4o → close this sub-node.
- Double-click the Basic LLM Chain node → set Source for Prompt (User Message) → Define below → paste into the Prompt field:
You are an email triage assistant. Here are today's unread emails as JSON:
{{ JSON.stringify($json.data) }}
Write a short Telegram morning digest:
- Start with "☀️ Good morning Rahul. X unread emails."
- "🔴 Need reply:" (sender + one-line why) — only genuinely personal/actionable
- "🟡 Worth reading:" max 3
- "⚫ Ignore:" just the count (newsletters, promos, notifications)
Keep it under 150 words. No markdown headers, just the emoji lines.
Execute step → OUTPUT shows your actual digest text. First AI run of the day. 🧠
2.6 Node 5 — deliver to Telegram
- + after the LLM Chain → search
telegram→ pick Telegram → Send a text message. - Settings:
- Credential: the bot from 2.1 (pre-selected).
- Resource: Message · Operation: Send Message.
- Chat ID: your numeric id from step 2.1-A (plain number, no expression needed).
- Text: click the field → switch to Expression → enter
{{ $json.text }}— the preview shows the digest. - Add Field → Append n8n Attribution → OFF (otherwise every message ends with an n8n ad).
- Execute step → 📱 your phone buzzes with the digest.
2.7 Test end-to-end, then make it live
- Back on the canvas, click Execute workflow (bottom center) — watch all five nodes light up green left to right.
- Click Publish (top right) → name the version (e.g.
v1) → Publish. - Tomorrow at 7:00 the digest arrives without you touching anything.
3 Custom domain + SSL (Cloudflare)
Routing your domain through Cloudflare gives you free edge SSL, DDoS protection, and webhook delivery that never depends on a lone VPS IP. This guide uses jarvis.jhooq.org — substitute your own domain everywhere.
3.1 Domain on Cloudflare
dash.cloudflare.com→ Add a domain → Connect a domain → enter your domain → Free plan → continue through the DNS review.- Cloudflare assigns 2 nameservers → set them at your registrar (Domains → your domain → Nameservers → custom) → wait for Cloudflare's "Active" email.
- DNS → Add record:
- Type A · Name
jarvis· IPv4 = your VPS IP (e.g.46.202.190.90). - Proxy status: Proxied 🟠 — traffic enters Cloudflare's network and your real IP stays hidden.
- Type A · Name
- SSL/TLS → Overview → encryption mode Full (plain Full, not "Full (strict)" — your origin's certificate carries the original
n8n-xxxx.srv…name, and plain Full accepts that).
3.2 Point n8n at the new domain
SSH into the VPS (or use hPanel's Browser terminal) and run — adjust the domain if yours differs:
cd /docker/n8n-* # your app dir — e.g. /docker/n8n-nohc
cp docker-compose.yml docker-compose.yml.bak
# 1) Traefik: also answer on jarvis.jhooq.org (the original URL keeps working)
sed -i 's#rule=Host(`${COMPOSE_PROJECT_NAME}.${TRAEFIK_HOST}`)#rule=Host(`${COMPOSE_PROJECT_NAME}.${TRAEFIK_HOST}`) || Host(`jarvis.jhooq.org`)#' docker-compose.yml
# 2) n8n: register all webhooks (Telegram!) on the armored address
sed -i 's#WEBHOOK_URL=https://${COMPOSE_PROJECT_NAME}.${TRAEFIK_HOST}/#WEBHOOK_URL=https://jarvis.jhooq.org/#' docker-compose.yml
docker compose up -d # recreate — workflows & credentials survive (n8n_data volume)
| Edit | Effect |
|---|---|
|| Host(`jarvis.jhooq.org`) | Traefik (reverse proxy) accepts requests for the new hostname |
WEBHOOK_URL=https://jarvis.jhooq.org/ | n8n registers future webhooks (Telegram trigger!) on the proxied domain |
3.3 Verify
- Open
https://jarvis.jhooq.org→ n8n loads with a green padlock (Cloudflare's edge certificate). - The old
https://n8n-xxxx.srvXXXXXXX.hstgr.cloudURL still works — nothing broke.
4 The assistant: brain + memory (W1)
4.1 Create the Telegram bot
- In Telegram, search @BotFather →
/newbot. - Display name: Jarvis · username: anything ending in
bot. - Copy the HTTP API token — treat it like a password (leak?
/revokeregenerates). - You'll also need an OpenAI API key:
platform.openai.com→ Billing (add credits) → API keys → create → copy immediately.
4.2 Telegram Trigger
- n8n → Create workflow → name it W1 - Assistant Core.
- Add first step → On app event → search Telegram → On message.
- Credential → Create new → paste the bot token → Save ✅.
- Test this trigger → message your bot within ~2 minutes (the test window expires!) → data appears → pin the output 📌.
4.3 AI Agent — brain and memory
- + after the trigger → AI Agent.
- ⚠️ Source for Prompt → Define below → drag the text field in → preview must show your message, not
undefined. - + under Chat Model → OpenAI Chat Model → your API key → gpt-4o.
- + under Memory → Simple Memory → Session ID = drag
chat > id→ window 5 (memory is per-chat — that's what makes it remember you). - System Message (Options → System Message):
You are Jarvis, Rahul's personal AI assistant. Be concise, friendly,
slightly witty. Answer in short messages suitable for Telegram.
If asked to do something you have no tool for yet, say that power
is coming soon.
4.4 Reply + publish
- + after the Agent → Telegram → Send a text message.
- Chat ID = drag
chat > idfrom the Telegram Trigger · Text = drag the Agent's output. - Turn off Append n8n Attribution (Add Field) — or every reply ends with an n8n ad.
- Publish — the webhook becomes permanent, no more 2-minute test windows.
- The memory test: "my name is Rahul" → then "what's my name?" → it remembers ✅.
4.5 Give the assistant your inbox (Gmail tool)
- Open W1 - Assistant Core → on the AI Agent node, click the + under "Tool".
- Search
gmail→ pick Gmail Tool. - Settings: Resource Message · Operation Get Many · Limit 20 · Simplify ON · Filter → Read Status Unread only (credential from Part 2 is pre-selected).
- Open the AI Agent node → extend the System Message:
You can read Rahul's Gmail with the Gmail tool. When asked about
email, fetch messages first, then summarize: group by urgency
(needs reply / important / ignore). Never invent emails.
Publish (edits aren't live until published!) → from your phone: "summarize my unread emails" → the 47→2 moment 🔥
5 Backups, updates & the time-travel demo
5.1 Snapshots & weekly backups
- hPanel → VPS → Snapshots & Backups.
- Create snapshot = manual save point before any risky change (one slot — a new snapshot overwrites the old).
- Backups = automatic weekly, with one-click restore.
5.2 The time-travel demo
- Snapshot the server.
- Change something visible — add
Always answer like a pirate.to the assistant's system message → publish → the bot answers "Arrr, ahoy!" 🏴☠️ - Restore the snapshot (~2–5 min downtime) → change is gone, bot is normal again.
5.3 Updating n8n safely
# 1. snapshot first (hPanel)
# 2. then:
cd /docker/n8n-* && docker compose pull && docker compose up -d
Version bumps, workflows intact. Turn on 2FA in n8n (Settings → Personal) while you're at it.
? Troubleshooting (webhooks, OAuth, gotchas)
Telegram trigger: "Listening…" but nothing arrives
The #1 gotcha. Check what Telegram thinks (paste in a browser with your token):
https://api.telegram.org/bot<TOKEN>/getWebhookInfo
"url": ""→ the 2-minute test window expired before your message arrived. Click Test this trigger again, send within ~30s. Once published, the webhook is permanent."pending_update_count" > 0→ messages queued, delivered on re-registration."last_error_message": "Connection timed out"→ Telegram can't reach your server (see below).
Webhook timeouts: the host's network drops Telegram's traffic
Symptom: bot replies sometimes, then goes silent; local curl to the webhook is instant, but
tcpdump -n 'tcp port 443 and (net 149.154.160.0/20 or net 91.108.4.0/22)'
shows zero inbound packets during Telegram retries → filtering upstream of your VPS.
Permanent fix — put webhooks behind Cloudflare (Part 3): with the record Proxied, Telegram connects to Cloudflare's network, which is never blocked. Verify with getWebhookInfo: ip_address should be a Cloudflare IP (188.114.x.x / 172.67.x.x).
DNS-cache gotcha: Telegram pins resolved IPs for hours. If it already learned your direct IP, re-register the webhook on a brand-new subdomain (fresh name = fresh lookup = Cloudflare immediately).
Google OAuth
- "Google hasn't verified this app" → normal for your own app: Advanced → Continue.
- New Google Cloud UI: the consent screen now lives under Google Auth Platform (Branding / Audience / Clients).
- One OAuth client serves Gmail, Calendar, Sheets… — reuse Client ID + Secret in each n8n credential.
AI Agent answers undefined
The Agent's prompt defaults to n8n's built-in chat (chatInput). With a Telegram trigger you must set Source for Prompt → "Define below" and map {{ $json.message.text }} — the preview under the field must show your actual message.
OpenAI "Rate limit reached"
Usually billing, not rate: API credits are separate from ChatGPT Plus. Check platform.openai.com → Billing. For big payloads (30 emails), trim fields with Aggregate → Specified Fields first.