Create the instance
In Vultr deploy a Cloud Compute instance with Ubuntu 24.04 LTS, the region closest to your users (Vultr lists Mexico City, several US cities, São Paulo, Europe and Asia), and your SSH public key. On 2026-10-19 the pricing page listed a 1 vCPU / 1 GB Regular Performance plan at $5.00/month, enough for most small bots. A $2.50 plan exists but is IPv6-only; use it only if every API your bot calls supports IPv6.
First login: user, SSH and firewall
ssh root@YOUR_SERVER_IP adduser --disabled-password --gecos "" admin usermod -aG sudo admin mkdir -p /home/admin/.ssh && cp ~/.ssh/authorized_keys /home/admin/.ssh/ chown -R admin:admin /home/admin/.ssh passwd admin # needed for sudo # disable password and root login over SSH printf 'PasswordAuthentication no\nPermitRootLogin no\n' > /etc/ssh/sshd_config.d/10-hardening.conf systemctl reload ssh ufw allow OpenSSH && ufw --force enable apt update && apt -y upgrade && apt -y install unattended-upgrades unzipOpen a second terminal and confirm
ssh admin@YOUR_SERVER_IPworks before closing the root session.Install Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh less nodesource_setup.sh # read before running sudo bash nodesource_setup.sh sudo apt -y install nodejs node --versionInstall the bot as an unprivileged user
sudo useradd --system --home /opt/mybot --shell /usr/sbin/nologin bot sudo mkdir -p /opt/mybot/data cd /tmp && curl -LO https://botnetwork.tech/downloads/telegram-grammy.zip sudo unzip -o telegram-grammy.zip -d /opt/mybot cd /opt/mybot && sudo npm install --omit=dev sudo install -m 600 /dev/null /opt/mybot/.env sudo nano /opt/mybot/.env # BOT_TOKEN=... MODE=polling sudo chown -R bot:bot /opt/mybotThe token file is readable only by the
botuser.Create the systemd service
/etc/systemd/system/mybot.service[Unit] Description=mybot chat bot After=network-online.target Wants=network-online.target [Service] Type=simple User=bot WorkingDirectory=/opt/mybot EnvironmentFile=/opt/mybot/.env ExecStart=/usr/bin/node src/index.js Restart=on-failure RestartSec=5 MemoryMax=256M NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true ReadWritePaths=/opt/mybot/data [Install] WantedBy=multi-user.targetsudo systemctl daemon-reload sudo systemctl enable --now mybot sudo systemctl status mybotFigure 2. A healthy service (illustration). Restart=on-failurebrings the bot back after a crash;enablestarts it on boot. TheProtect*lines limit what a compromised bot could touch. Generate a unit for your own setup with the hosting config generator.Logs, updates and backups
journalctl -u mybot -f # follow logs sudo systemctl restart mybot # after changing code or .env sudo unattended-upgrade --dry-run # security updates run dailyVultr's pricing page (verified 2026-10-19) says automatic backups add 20% to the instance price. Your bot's data folder can also be copied off the server with a cron job. vultr.com/pricing
Troubleshooting
- status=203/EXEC: the ExecStart path is wrong. Run
which nodeand fix it. - EACCES / read-only file system: ProtectSystem=strict blocks writes outside ReadWritePaths. Put files in /opt/mybot/data.
- Webhook mode: you then need a domain, TLS and a reverse proxy (Caddy or nginx) on 443, and ufw allow 443. Long polling avoids all of that.