SSD Nodes Learn Hosting plans →
How to do am Matt ConnorBy Matt Connor · Updated 2026-08-13

How to self-host Iva Telegram AI assistant for VPS

Run Iva v0.3.13 for Telegram on small VPS without open ports or domain. Use outbound long polling, systemd user services, and back up Obsidian markdown memory.

Wetin you dey build

Iva na self-hosted Telegram AI assistant, and e be one of the few wey you fit deploy without opening inbound port or pointing domain to am. Certificate no dey too, because nothing for the box dey listen for public network. The service dey connect out to Telegram, keep the connection open, and read your messages from the reply. Everything else come from that one outbound connection.

Iva get MIT license and dem write am for Node. E dey keep memory for folder of plain markdown files wey Obsidian fit open directly, so the notes wey e keep about you remain readable without the app. This guide pin release v0.3.13, wey dem publish on 6 August 2026.

Most self-hosted software dey start with DNS (domain name system) record and Let's Encrypt certificate wey Certbot issue. Iva skip that layer completely, na why small VPS behind firewall wey only allows SSH fit be complete deployment.

Why Iva no need open ports

iva-telegram-poll.service na long polling bridge. E call Telegram's getUpdates API and dey wait for answer, so na your server dey start every connection. Telegram no dey connect back, so you no need configure reverse proxy or remember certificate renewal.

The agent itself dey listen for 127.0.0.1 port 8723 only. Project documentation talk am clearly: no expose port 8723, and any reverse proxy wey you put in front of am must keep the bearer token requirement. Check the bind address after installation.

sudo ss -tlnp | grep 8723

The address must read 127.0.0.1:8723. Wildcard address like 0.0.0.0:8723 mean say people fit reach the agent's HTTP routes from internet, and you suppose fix am before you send any private thing to the bot.

So firewall remain closed. Allow SSH before you enable am, because ufw enable without SSH rule go close the session wey you dey type inside.

sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status

Wetin the one line installer dey actually do

The project's front page give you one command wey pipe script from GitHub enter bash. Read the script first, because e dey do much more than install one program.

curl -fsSL https://raw.githubusercontent.com/smixs/iva/main/install.sh -o iva-install.sh
less iva-install.sh
  • E install system packages with the package manager wey e detect: git, gh, python3, ffmpeg, pandoc and poppler-utils.
  • E create 2 GB swapfile for /swapfile when the box get less than 1.5 GB RAM and no swap, because the build go die without am.
  • E install nvm, then Node 24, wey be the minimum version wey Iva dey run on.
  • E install uv, the Python package manager, inside ~/.local/bin.
  • E clone the repository go ~/iva and run npm ci.
  • E install two global npm packages, agent-browser (wey later download Chromium) and @googleworkspace/cli.
  • E run the setup wizard, build the project, and create the vault.
  • E write iva command inside ~/.local/bin and install the systemd user units.

Software plenty for one line. This one also explain why the README tell you make you install am as ordinary user and no be root: the agent's shell tool go later run with the privileges wey installer get. The script call sudo only for the package installs and the swapfile, through one helper wey dey run commands directly when you already be root.

Create dedicated user before you install

Give Iva its own account. The agent dey run shell commands for host through Node's child_process, without container or sandbox. So, the account wey e dey run under na the security boundary.

sudo adduser --disabled-password --gecos "" iva
sudo usermod -aG sudo iva
sudo install -d -m 700 -o iva -g iva /home/iva/.ssh
sudo cp ~/.ssh/authorized_keys /home/iva/.ssh/authorized_keys
sudo chown iva:iva /home/iva/.ssh/authorized_keys
sudo chmod 600 /home/iva/.ssh/authorized_keys
sudo loginctl enable-linger iva

enable-linger matter because Iva dey run as systemd user units. Without linger, systemd go stop that user's services immediately their last session end. This mean the assistant go die when you close SSH. The same rule apply to any service and timer wey you write yourself under systemd.

The account need sudo only while installer dey add packages. Remove am after installation finish.

sudo deluser iva sudo

Log in directly as that user through SSH. Shell wey you enter with sudo -iu iva no get DBUS_SESSION_BUS_ADDRESS or XDG_RUNTIME_DIR set. So, every systemctl --user command go fail with Failed to connect to bus. This boundary na the same kind work as running services under users with least privilege.

Install pinned release instead of piping go bash

The installer get one useful property. Before e clone anything, e dey check whether the directory wey the script dey inside already get a package.json wey contain "eve". If e get am, e go build that checkout and skip the clone. So you fit choose the version by yourself.

git clone --branch v0.3.13 https://github.com/smixs/iva.git ~/iva
cd ~/iva
git log -1 --oneline
bash install.sh

Now you know which code dey run. You no know that when the script clone main for any state wey e happen dey that hour. Iva release five versions between 4 and 6 August 2026, so main this morning and main this afternoon no be the same program.

Tag checkout go leave git for detached HEAD state. E go run well, but understand the limit: iva update go move the checkout forward onto the update branch, so the pin na known starting point, no be permanent freeze. iva version go print the package version and git commit, so you fit always see where you dey.

To move go later release deliberately, list the tags, set IVA_TAG to the one wey you pick, then run the installer again from inside the checkout.

cd ~/iva
git fetch --tags
git tag --list 'v*' | sort -V | tail -5
IVA_TAG=v0.3.13
git checkout "$IVA_TAG"
bash install.sh --skip-setup
iva restart

--skip-setup stop the wizard from running again over a .env wey already dey work.

Wetin the five wizard steps be, and the keys wey dem ask for

  1. Model provider and model. MODEL_PROVIDER accepts opencode, ollama, openrouter or codex. The wizard dey validate the key live and list the models wey your plan offer.
  2. Voice and search. Deepgram key dey transcribe voice notes. Web search key (Tavily, Exa, Parallel or Brave) na optional.
  3. Telegram bot token from @BotFather. The wizard dey check am against getMe endpoint.
  4. Access control. You go send message to your bot, and the wizard go read your numeric user ID from getUpdates.
  5. System settings. IANA timezone, vault directory, and local port, wey be 8723 by default.

Two of these na dependencies wey the “one command” framing dey hide. Iva no ship with model, so e need paid model plan or API key before e fit answer anything. E no dey transcribe audio by itself too, so voice notes need separate service. Deepgram's nova-3 model with DEEPGRAM_LANGUAGE=multi dey detect the language, and new Deepgram accounts dey get starter credits wey fit cover months of personal use. Text go work with only the model key. Na only voice depend on Deepgram.

Check wetin the wizard write.

grep -E '^(MODEL_PROVIDER|TELEGRAM_ALLOWED_USER_IDS|ASSISTANT_VAULT_DIR|IVA_PORT)=' ~/iva/.env
ls -l ~/iva/.env

ls suppose print -rw-------, mode 0600, because that file hold every key wey you just paste. TELEGRAM_ALLOWED_USER_IDS must hold your numeric ID. The allowlist dey fail closed, so empty value mean say Iva no go answer anybody.

The model dey read once when process start. If you edit MODEL_PROVIDER or model name for .env, e no go change anything until you run iva restart. For openrouter, the model name na vendor slug like anthropic/claude-sonnet-4.5, no be bare name. For codex, no API key dey at all: iva login go sign in to existing ChatGPT subscription.

Iva dey cost how much to run every month

ChartMonthly cost of a self-hosted Iva, published list prices, August 2026
The data behind this chart
[
  {
    "plan": "Small VPS, always on",
    "usd_per_month": 5
  },
  {
    "plan": "OpenCode Go model plan",
    "usd_per_month": 5
  },
  {
    "plan": "Ollama Cloud model plan",
    "usd_per_month": 20
  },
  {
    "plan": "Deepgram voice, starter credits",
    "usd_per_month": 0
  },
  {
    "plan": "Tavily web search, free tier",
    "usd_per_month": 0
  },
  {
    "plan": "Cheapest complete setup",
    "usd_per_month": 10
  }
]

Dis na published list prices as of August 2026, no be measurements. Small VPS wey cost 5 US dollars plus OpenCode Go plan wey cost 5 dollars na the cheapest complete setup, about 10 dollars every month. Ollama Cloud na the other flat-rate option wey cost 20 dollars, and its frontier models dey bill extra usage on top the plan. Voice dey cost 0 while the Deepgram starter credits still last.

OpenRouter no get row here because e dey use pay-as-you-go billing, so your bill dey follow your usage. Na this option you need monitor well: assistant wey dey carry 131072 token context window enter every turn fit spend pass flat plan quick. Set the context window variable to the model real size, because inflated value go only waste tokens.

Services two and timers two

  • iva.service dey run the agent itself.
  • iva-telegram-poll.service dey run the long polling bridge wey dey talk to Telegram.
  • iva-memory-doctor.timer dey fire for 05:00 and run the nightly maintenance pass for the vault.
  • iva-update-check.timer dey fire for 10:00 and check whether newer release dey.
  • iva-telegram-userbot.service dey exist only if you set up the optional Telethon proxy.
iva status
systemctl --user status iva.service iva-telegram-poll.service
systemctl --user list-timers
iva logs poll

iva status dey report both services and both watchdog timers. systemctl --user list-timers dey print the next run time for each timer. Na so you confirm say the memory doctor go really run tonight. Both services suppose dey for active (running). If one dey restart continuously, journalctl --user -u iva.service -n 100 go show the reason.

This split important when you dey debug. The bridge fit dey alive and dey poll while the agent dey down. Then Telegram go accept your message, but nothing go answer am. iva logs poll dey follow the bridge, while iva logs dey follow the agent. So, the two logs go tell you which part get problem.

Weda Obsidian vault dey, and how to back am up

ASSISTANT_VAULT_DIR dey default to vault inside install directory, so memory dey for ~/iva/vault. E be im own git repository, separate from code, and na this one allow you update Iva without touching your notes.

  • vault/CORE.md dey keep durable facts and standing preferences, with limit of 1200 characters, and e dey enter every system prompt.
  • vault/daily/YYYY-MM-DD.md na transcript for the day, and system dey only append to am.
  • vault/cards/ dey keep typed cards for contacts, projects, decisions, ideas and notes.
  • vault/summaries/daily/, weekly/, monthly/ and yearly/ dey keep the rollups.
  • vault/attachments/ dey keep files by date, while vault/.graph/ dey keep the link graph.
  • vault/schema.json dey define card types and decay rules.

Rollups dey run according to schedule inside the process. Daily pass for 04:00 dey turn yesterday transcript into cards and summary, and rewrite CORE.md. After that, weekly, monthly and yearly passes dey compress dem one after another. For 05:00, memory doctor dey run deterministic pass wey no model dey involved: e enforce schema, rebuild link graph, regenerate index, then commit and push.

That push na your backup, and na the step wey people dey miss. If vault no get git remote, doctor go try create private GitHub repository through gh. E need authenticated GitHub CLI.

gh auth login
systemctl --user start iva-memory-doctor.service
cd ~/iva/vault && git log --oneline -3

Commit wey get today date mean say pass run and vault don commit. gh not available warnings for log mean the opposite: system dey maintain vault, but e never leave the server. So, dead VPS fit carry your memory comot with am.

Keep another copy wey you control too.

tar czf ~/iva-vault-backup.tgz -C ~/iva vault

Copy that file comot from the box with scp, then delete am from server. To read the memory for Obsidian, point Obsidian to a clone of the vault repository. Wikilinks and backlinks go work as dem be, and graph view go work too. You fit safely edit cards and CORE.md by hand. Leave MOC.md and .graph/ alone, because nightly pass dey regenerate both.

Treat the vault like your life log

That directory na dated record of wetin you talk, who you meet, and wetin you decide, for one machine wey you rent. Two things follow from this.

Self-hosting dey move the storage, not the processing. Every turn dey go your model provider, and every voice note dey go Deepgram. The vault na your own. But the companies wey dey serve the requests still fit see the requests. Running the memory layer yourself, like one Mem0 memory server for your own VPS, get the same setup: the store dey local, while the model call still comot from your machine. If one subject too sensitive for third party, no put am for the chat.

That account fit reach the whole vault. Iva tools dey run host native through Node's fs and child_process, without Docker or sandbox, so if person hijack one turn, e get whatever access the service user get. Na why the account no get any sudo after the install, and why you need give the allowlist more attention than e first look: na the gate wey decide whose messages go become commands for your server. If you want the assistant for your pocket without opening anything, na the same pattern wey dem use to reach self-hosted Hermes agent from your phone, with the chat client doing the work wey public endpoint for normally do.

Wetin fit break, and the message wey you go see

Build get killed, exit 137. Kernel out of memory killer kill the build. Installer dey add swap only when RAM dey below 1.5 GB and swap no dey exist, so add swap by yourself and run installer again.

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
free -h

Failed to connect to bus. Every systemctl --user command dey print this when shell no get user session bus, na wetin sudo -iu iva dey provide. Open normal SSH session as that user, or export XDG_RUNTIME_DIR=/run/user/$(id -u iva) before the command.

Bot no dey respond to you. TELEGRAM_ALLOWED_USER_IDS empty, and allowlist dey fail closed. Send message to the bot: e go reply with your numeric ID and nothing else. Put that ID inside .env and run iva restart.

Bot go silent immediately after iva config. Wizard fit move IVA_PORT without updating ASSISTANT_HOST, so bridge go connect to port wey nothing dey answer. Compare the two lines, then restart.

grep -E '^(IVA_PORT|ASSISTANT_HOST)=' ~/iva/.env
iva restart

Voice note no get reply. Telegram's Bot API no dey allow file downloads wey pass 20 MB, so bridge no go receive long audio and e no get anything to send Deepgram. Split the file before you send am.

ffmpeg -i long.ogg -f segment -segment_time 600 -c copy part-%02d.ogg

Turn dey hang and e no dey answer. Wedged workflow state dey survive restart and e dey queue itself again, so restart alone no dey clear am. iva reset dey quarantine that state and restart both services. /new for the chat go start fresh conversation.

Chromium fail for Ubuntu 24.04. Ubuntu 24.04 dey block unprivileged user namespaces through AppArmor, so Chromium own sandbox no fit start and agent-browser dey fail. Installer dey work around am by writing "--no-sandbox" inside ~/.agent-browser/config.json. Know say this setting dey there. E dey reduce browser isolation, and na another reason why the account suppose own nothing except Iva.

FAQ

Iva dey need domain or open port to self-host?

No. Iva dey talk to Telegram with long polling: iva-telegram-poll.service dey call getUpdates and wait, so every connection dey go out from your server. Nothing need reach the server from outside, so you no need DNS record or certificate. The agent own HTTP port, 8723, dey bind to 127.0.0.1, and project documentation tell you make you no expose am. Firewall wey allow SSH and nothing else na the correct configuration.

How much e dey cost to run Iva every month?

For published August 2026 list prices, small VPS wey cost 5 dollars plus the cheapest flat rate model plan wey cost 5 dollars go total about 10 US dollars every month. Ollama Cloud go cost 20 dollars instead, and e still bill frontier models on top. Deepgram starter credits cover voice at first, and web search tiers get free allowances. OpenRouter na pay as you go, so e no get fixed monthly amount.

Where Iva dey keep my data, and how I fit back am up?

For ~/iva/vault by default, and ASSISTANT_VAULT_DIR dey set am. Na separate private git repository of plain markdown: CORE.md, daily/YYYY-MM-DD.md, cards/ and summaries/. The 05:00 memory doctor dey commit and push am, but this one only help if the repository get remote, so run gh auth login or add your own remote during setup. Keep offline copy too with tar czf ~/iva-vault-backup.tgz -C ~/iva vault and move that file comot from the server.

My data private if I self-host Iva?

The storage na your own. The processing no be. The vault dey remain for your disk until you push am, and .env dey use mode 0600 and service user own am. Model calls and voice transcription na cloud APIs, so those messages dey pass through your model provider and Deepgram. Iva get MIT license, so you fit read exactly wetin e send and change am. Telegram allowlist dey fail closed, meaning say empty TELEGRAM_ALLOWED_USER_IDS go block everybody, including you.

Which model providers Iva support?

MODEL_PROVIDER dey accept opencode (OpenCode Go), ollama (Ollama Cloud), openrouter and codex. OpenRouter dey use vendor slug like anthropic/claude-sonnet-4.5 and e offer the widest choice of models. codex dey sign in to existing ChatGPT subscription with iva login and e no use API key. Set the provider, set the matching context window to the model real size, then run iva restart, because the model dey read once when process start.