Over 21,000 publicly exposed bot instances were found running with zero authentication in early 2026, API keys, wallet access, and chat logs sitting wide open to anyone who scanned the right port range. That wasn't a hosted platform getting breached. Those were self-hosted deployments, people running their own bots on their own servers, who skipped the boring infrastructure work and paid for it.
I run my own Freqtrade instance on a $12/month Hetzner box (the same one behind the build-in-public bot I write about in my journey series). Self-hosting a trading bot gives you control a hosted platform like Bitsgap or 3Commas will never give you: your own strategy code, no monthly fee tied to account size, no platform risk if the company folds. But it also means you are now the security team. Nobody patches your server for you. Nobody rotates your keys. Nobody notices if your bot process died three days ago and your positions have been sitting unmanaged since Tuesday.
Honestly, most of the self-hosted horror stories I hear aren't sophisticated hacks. They're a forgotten firewall rule, a .env file committed to a public GitHub repo, or an API key with withdrawal permission that never should've existed. Here's the checklist I actually run, in the order I run it.
API key scoping: trade-only, always
This is the single highest-leverage thing on this list, and it's also the AlgoGrade house rule: every bot API key gets trade-only permissions, no withdrawal, full stop. No exceptions for "just testing." No exceptions because a tutorial said to enable everything.
The logic is simple. If your key is scoped to place and cancel orders only, the worst case when a key leaks is someone trades your account into a bad position, annoying but recoverable. If the key has withdrawal permission, the worst case is your account balance goes to zero and lands in a wallet you'll never trace. Freqtrade's own setup guidance is blunt about this: enable read and trading permissions, and explicitly disable withdrawal permissions on the exchange side, applying the principle of least privilege to the key itself (see Freqtrade's exchange configuration notes).
Beyond withdrawal scoping, two more habits matter:
- IP whitelist the key to your server's static IP. Every major exchange supports this. It means even a leaked key is useless from anywhere but your box.
- Rotate keys on a schedule, not just after an incident. Every 90 days is what I do. It's mildly annoying to update the config and restart the bot. It's a lot less annoying than explaining to yourself why you never rotated a key that got scraped off an old server snapshot.
I've made this mistake before, or close to it. Early on I had a key with margin trading enabled that I genuinely didn't need for a spot-only strategy. Nothing happened, but if that server had been compromised the blast radius would've been bigger than it needed to be for no reason. Scope the key to exactly what the bot does, not what it might do someday.
Server hardening: the stuff that's boring until it isn't
If you're running Freqtrade, Hummingbot, or your own Python bot on a VPS (Ubuntu or Debian, almost everyone I know uses one or the other), the baseline hardening is not exotic. It's maybe 45 minutes of setup once:
SSH key auth only, password login disabled. Set PasswordAuthentication no in sshd_config. Bots get brute-forced on port 22 constantly, it's automated internet background noise, not a targeted attack, but it's still a door you should lock.
A firewall that denies by default. ufw or iptables, allow only the ports you actually need: SSH (ideally on a non-standard port, which does approximately nothing against a targeted attacker but cuts automated scan noise by a lot), and nothing else exposed publicly. Your bot's own web UI, if it has one, should never face the internet directly.
That last point deserves its own paragraph because it's the exact failure mode behind those 21,000 exposed instances. Freqtrade's REST API and FreqUI listen on localhost by default for a reason. The docs are explicit: "we strongly recommend to not expose this API to the internet." If you want to check your bot's dashboard from your phone, use an SSH tunnel or a WireGuard VPN into the box, not a port forward to 0.0.0.0. I check mine through a tunnel on my phone's Termux app. Takes ten extra seconds, saves you from being scan-result number 21,001.
Fail2ban for SSH. Free, five minutes to install, bans IPs after a handful of failed login attempts. Doesn't stop a determined attacker but kills the noise from automated botnets probing every VPS on the internet.
Unattended security updates. unattended-upgrades on Ubuntu applies security patches automatically. A trading bot server that never gets rebooted or patched is running increasingly stale, increasingly vulnerable software the longer it sits.
If you do only three things from this whole post: scope every API key to trade-only with no withdrawal, bind your bot's dashboard to localhost behind a VPN or SSH tunnel, and never put a raw API key or secret in a public repo. Those three cover most of the actual incidents I've seen or heard about.
Secrets management: get it out of your codebase
This is where I see the most self-inflicted damage. People write their strategy in a public or semi-public GitHub repo (to show off, to collaborate, to back it up) and the API key lives in a config file that gets committed right along with it. In April 2026, a breach at Vercel, a platform many crypto teams use to host dashboards and frontends, led to a wave of developers scrambling to rotate keys because credentials had been sitting in environment variables tied to a compromised third-party integration (see CoinDesk's coverage of the incident). Nobody's account got drained in that specific case as far as anyone can confirm, Vercel says sensitive env vars weren't readable, but the scramble itself tells you how normal it's become to have API credentials sitting somewhere you didn't fully account for.
Practical version for a solo bot operator:
- .env files, never in the repo. Add
.envto.gitignorebefore you write a single line of strategy code, not after. - A secrets manager if you're running more than one bot or server. Even something lightweight like Doppler or a self-hosted Vaultwarden instance beats plaintext config files scattered across servers.
- Different keys per bot, per exchange, per server. If one leaks, you're rotating one key, not auditing your entire footprint to figure out what else that key touched.
I'll admit I was sloppier about this in 2021 than I am now. Kept a strategy repo private but had the API key in a config file inside it for a solid year before I bothered separating secrets out properly. Nothing bad happened. That's not the same as it being fine, it's just luck holding.
Network exposure and monitoring: know when it breaks
A bot that silently stops working is arguably worse than one that never ran, because you think you're covered and you're not. The 21,000-instance scan mentioned above found exposed dashboards specifically because those operators had no idea their bot's control panel was internet-facing in the first place. Nobody was watching.
Minimum monitoring I'd consider non-negotiable:
- A heartbeat check. A cron job that pings your bot's health endpoint (or checks the process is alive) every few minutes and alerts you (Telegram bot message, email, whatever you'll actually see) if it stops responding.
- Balance and position alerts. If your account balance or open position count changes outside expected bounds, you want to know within minutes, not when you happen to check the app three days later.
- Log aggregation somewhere off the box. If the server itself gets compromised or corrupted, you want logs that survive that, even just shipping them to a second cheap VPS or a log service works.
I run a dumb but effective version of this: a five-line script on a second, separate cheap VPS that curls my bot's status endpoint every 5 minutes and pings my phone if it doesn't get a 200 response twice in a row. Cost to run: basically nothing. Value the one time my bot process silently died during a exchange API outage: probably saved me from an unmanaged position sitting open overnight.
Backup and recovery: your server will die eventually
Not if. When. VPS providers have outages, drives fail, you'll fat-finger an rm -rf in the wrong directory at some point (I have, on a test box, thankfully). What you actually need backed up for a trading bot:
- Strategy code and config, obviously, but this is the easy part if you're using git properly.
- Trade history and state files, which for Freqtrade means the SQLite database tracking open and closed trades. Lose this and you can still trade, but you lose your own performance record and any state the bot needs to reconcile with the exchange on restart.
- Environment secrets, encrypted, stored somewhere that isn't the same server (a password manager, an encrypted vault, anything that survives the server dying).
For the actual backup mechanism, something like restic handles encrypted, incremental backups to remote storage without much fuss, point it at S3-compatible storage or a second server and put it on a cron schedule. I run mine nightly. It's not glamorous work and I put it off for probably four months longer than I should have when I first set up my bot server.
Recovery matters more than backup. A backup you've never restored from is a backup you don't actually have. I test a full restore onto a fresh VPS roughly every quarter, mostly because the first time I needed a real restore (a Hetzner box that got stuck mid-reboot for reasons I never fully figured out) I discovered my backup script had been silently failing for two weeks. The bot kept trading. The backups just weren't happening. Would've found out the hard way at the worst possible time.
Self-hosted vs hosted: what you're actually trading off
None of this is an argument that self-hosting is wrong, I do it, and I'd do it again. But it's worth being honest about the actual tradeoff against a hosted platform, since a lot of people compare price and features and skip the operational side entirely.
| Feature | Self-hosted (Freqtrade/Hummingbot) | Hosted (Bitsgap/3Commas) |
|---|---|---|
| Monthly cost | $5-20 VPS | $29-149 |
| Server security is your job | ||
| Uptime monitoring included | ||
| Custom strategy code | ||
| Support team if something breaks | ||
| Platform shutdown risk |
If reading this checklist felt like a chore, that's useful information about yourself, not a character flaw. A hosted platform trades some cost and flexibility for someone else owning the uptime, patching, and monitoring problem. We've covered that ground before in our platform vetting guide and our Bitsgap vs Pionex comparison, and the custody question there rhymes with the security question here: someone has to own this operational surface, either you or a company you're paying to.
If you're self-hosting because you want full control of a custom strategy, that's a legitimate reason and this checklist is the cost of admission. If you're self-hosting purely to save $50 a month and you're not going to actually do the hardening, honestly, you might be better off on a hosted platform and putting that saved time into your actual strategy instead. [AFFILIATE: Bitsgap]
I don't have a clean number for how many self-hosted bots out there are running with none of this in place. Based on that 21,000-instance scan alone, I'd guess it's a lot more than the people running them would like to admit.

