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 dey among 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 to public network. The service dey connect out to Telegram, keep the connection open, and read your messages from the reply. Everything else follow from that one outbound connection.
Iva get MIT license and dem write am for Node. Its memory na folder of plain markdown files wey Obsidian fit open directly, so the notes wey e keep about you remain readable even without the app. This guide pin release v0.3.13, wey dem publish on 6 August 2026. The repository don later change name from smixs/iva to smixs/iva-agent, and the commands below dey use the new name.
Most self-hosted software dey start with DNS (domain name system) record and Let's Encrypt certificate wey dem issue with Certbot. Iva skip that layer completely, na why small VPS wey firewall allow only 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 8723The 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 statusWetín the one line installer dey actually do
The project 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-agent/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,pandocandpoppler-utils. - E create 2 GB swapfile for
/swapfilewhen the box get less than 1.5 GB RAM and no swap, because build go die without am. - E install nvm, then Node 24, wey be the minimum version Iva dey run on.
- E install
uv, the Python package manager, into~/.local/bin. - E clone the repository go
~/ivaand runnpm ci. - E install
agent-browseras global npm package. The package then download Chromium, and put the Google Workspace CLI,gws, under~/.localwithout sudo. - E run the setup wizard, build the project, and create the vault.
- E write an
ivacommand into~/.local/binand install the systemd user units.
Na plenty software for one line. E also explain why the README tell you make you install as ordinary user and no be root: the agent shell tool go later run with the same privileges wey installer get. The script dey call sudo only for package installs and swapfile, plus maybe one more time for the Chromium step, through one helper wey run commands directly when you don already dey 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 ivaenable-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 sudoLog 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 am go bash
The installer get one useful behaviour. Before e clone anything, e dey check whether the directory wey script dey inside already get package.json containing "eve". If e get am, e 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-agent.git ~/iva
cd ~/iva
git log -1 --oneline
bash install.shNow you know which code dey run. You no know that one 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 leave git for detached HEAD state. E go run fine, but understand the limit: iva update move the checkout forward onto the update branch, so the pin na known starting point, no be permanent freeze. iva version print the package version and the git commit, so you fit always see where you dey.
To move go later release by choice, list the tags, check out the one wey you choose in place of v0.3.13 below, then run the installer again from inside the checkout. The installer itself no get setting for release tag. Its documented environment variables na REPO_URL, BRANCH and INSTALL_DIR, so na the git checkout alone dey do the pinning.
cd ~/iva
git fetch --tags
git tag --list 'v*' | sort -V | tail -5
git checkout v0.3.13
bash install.sh --skip-setup
iva restart--skip-setup stop the wizard from running again over .env wey already dey work. Run iva version afterwards to confirm the commit wey you land on.
Wetin the five wizard steps be, and the keys wey dem ask for
- Model provider and model.
MODEL_PROVIDERacceptsopencode,ollama,openrouterorcodex. The wizard dey validate the key live and list the models wey your plan offer. - Voice and search. Deepgram key dey transcribe voice notes. Web search key (Tavily, Exa, Parallel or Brave) na optional.
- Telegram bot token from @BotFather. The wizard dey check am against
getMeendpoint. - Access control. You go send message to your bot, and the wizard go read your numeric user ID from
getUpdates. - 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/.envls 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 cost to run every month na how much
Di data wey dey behind dis chart
[
{
"plan": "Small VPS, always on",
"usd_per_month": 5
},
{
"plan": "OpenCode Go model plan",
"usd_per_month": 10
},
{
"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": 15
}
]These na published list prices as of October 2026, no be measurements. Small VPS wey cost 5 US dollars plus OpenCode Go plan wey cost 10 dollars na the cheapest complete setup, about 15 dollars every month. OpenCode own Go page list this monthly price without first-month discount, and Iva README talk say the same setup cost about 14 to 15 dollars altogether. Ollama Cloud na the other flat-rate option at 20 dollars for the Pro plan, and dem go bill usage wey pass the credits wey the plan include separately. Voice cost 0 while the Deepgram starter credits still dey.
OpenRouter no dey this table because na pay-as-you-go, so your bill dey follow your usage. Na this option you need monitor: assistant wey dey carry 131072-token context window enter every turn fit spend pass flat plan quickly. Set the context window variable to the model real size, because value wey too high only dey waste tokens.
Services two and timers two
iva.servicedey run the agent itself.iva-telegram-poll.servicedey run the long polling bridge wey dey talk to Telegram.iva-memory-doctor.timerdey fire for 05:00 and run the nightly maintenance pass for the vault.iva-update-check.timerdey fire for 10:00 and check whether newer release dey.iva-telegram-userbot.servicedey 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 polliva 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.mddey keep durable facts and standing preferences, with limit of 1200 characters, and e dey enter every system prompt.vault/daily/YYYY-MM-DD.mdna 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/andyearly/dey keep the rollups.vault/attachments/dey keep files by date, whilevault/.graph/dey keep the link graph.vault/schema.jsondey 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 -3Commit 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 vaultCopy 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 -hFailed 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 restartVoice 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.oggTurn 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
I need domain or open port to self-host Iva?
No. Iva dey talk to Telegram through long polling: iva-telegram-poll.service dey call getUpdates and wait, so na your server dey start every connection go outside. Nothing need reach the server from outside, so you no need DNS record or certificate. 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 October 2026 list prices, small VPS wey cost 5 dollars plus the cheapest flat-rate model plan wey cost 10 dollars go reach about 15 US dollars every month. Ollama Cloud cost 20 dollars instead, and e go bill usage wey pass the credits wey dey included on top. Deepgram starter credits fit 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?
By default, e dey for ~/iva/vault, 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 work if the repository get remote. So run gh auth login or add your own remote during setup. Also keep offline copy 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 your own. The vault go remain for your disk until you push am, and .env dey mode 0600, owned by the service user. 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 dey send and change am. Telegram allowlist dey fail closed, meaning empty TELEGRAM_ALLOWED_USER_IDS go block everybody, including you.
Which model providers Iva support?
For the pinned v0.3.13 release, 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. Later releases add more routes, including Claude subscription and custom OpenAI compatible endpoint. Set the provider, set the matching context window to the model real size, then run iva restart, because the model dey read only once when process start.