Bootstrap a VPS to run Claude Code with the Telegram plugin and the KAppMaker CLI skill. Once set up, you can drive your KAppMaker workflows (create apps, generate logos, configure stores, build & publish Android releases) from Telegram on your phone.
On a fresh Ubuntu/Debian VPS:
curl -fsSL https://raw.githubusercontent.com/KAppMaker/KAppMakerDeveloperBot/main/setup-vps.sh | bashOr, if you'd rather review first:
wget https://raw.githubusercontent.com/KAppMaker/KAppMakerDeveloperBot/main/setup-vps.sh
less setup-vps.sh
bash setup-vps.shThe script is idempotent — re-running it skips anything already installed.
| Component | Version | Purpose |
|---|---|---|
git, curl, tmux, unzip, build-essential |
latest | Base tooling |
python3, pip, venv |
system | Used by some KAppMaker tools |
| Temurin JDK | 17 | Required for Android Gradle Plugin / KMP |
Android SDK cmdline-tools + platforms;android-34 + build-tools;34.0.0 |
latest | Build & sign APK/AAB on the VPS |
| Gradle | 9.4.1 | Standalone Gradle (project wrappers override this) |
| Node.js | 22 | Runtime for Claude Code |
| Bun | latest | Required by the Telegram plugin |
| Claude Code | latest | @anthropic-ai/claude-code global npm |
| KAppMaker CLI | latest | kappmaker global npm — used by the kappmaker plugin |
GitHub CLI (gh) |
latest | Push generated app repos to GitHub |
cloudflared |
latest | Cloudflare quick tunnels for web (Wasm/JS) preview URLs |
preview / preview-stop |
bundled | Helper scripts in ~/bin that wrap cloudflared for one-command preview links |
Environment variables (JAVA_HOME, ANDROID_SDK_ROOT, ANDROID_HOME, BUN_INSTALL, PATH) are persisted to ~/.bashrc in a marked block.
A ~/projects/ directory is created with two workspace files:
CLAUDE.md— workspace-wide rules: project switching ("switch to fittracker"), project lifecycle, kappmaker-first workflow, build previews, asset attachment, safety confirmations, and Telegram output style.MEMORY.md— user-controlled persistent memory. Empty by default; you populate it via Telegram with messages like "remember: all new repos should be private" / "forget X" / "what do you remember". Claude reads it before every meaningful task and respects it (memory entries override CLAUDE.md defaults when they conflict).
Each app you create lives in its own subdirectory and can have its own CLAUDE.md for project-specific rules.
The script prints these steps when it finishes; they can't be automated.
Note: the bootstrap script runs
kappmaker config initinteractively at the end. If for any reason it was skipped (e.g. no TTY), run it manually before doing anything else:kappmaker config init. Docs: https://cli.kappmaker.com/.
-
Reload shell
source ~/.bashrc
-
Log into Claude with your Pro/Max subscription
cd ~/projects claude
Open the printed URL in your laptop browser, paste the auth code back. Always start Claude from
~/projectsso the workspace CLAUDE.md is loaded. -
Install plugins (inside Claude)
/plugin marketplace add KAppMaker/KAppMaker-CLI /plugin install kappmaker@KAppMaker-CLI /plugin marketplace add anthropics/claude-code /plugin install telegram@anthropic -
Configure Telegram with your BotFather token
/telegram:configure -
Pair your Telegram account
/telegram:accessSend
/startto your bot from Telegram, then approve the pairing in the terminal. -
Run inside tmux with the Telegram channel active so Claude listens for your bot messages and survives SSH disconnect
tmux new -s claude cd ~/projects && claude --channels plugin:telegram@claude-plugins-official
Detach:
Ctrl+BthenD· Reattach:tmux attach -t claudeImportant: plain
claude(without--channels) starts a normal interactive session and does not listen on Telegram. The--channelsflag is what opens the listener. -
Log into GitHub CLI for app repo pushes
gh auth login
Use the dedicated bot account from the GitHub authentication section below — don't use your personal account on the VPS.
A VPS can be compromised. If your personal GitHub credentials live on it, an attacker gets your private repos, can force-push to main, etc. Use a dedicated machine user account instead — fully isolated, easy to revoke.
-
Create a separate GitHub account for the bot (free). Use a
+alias on your email so it lands in your inbox:you+kappmakerbot@gmail.com→ register at https://github.com/signup. Enable 2FA on it (separate authenticator entry from your personal one). -
Add it to your
KAppMakerorg with the Member role (browser):- Org → People → Invite member
- Repos it needs to push to → Manage access → grant write
-
Generate an SSH key on the VPS for this account:
ssh-keygen -t ed25519 -C "kappmaker-bot-vps" -f ~/.ssh/kappmaker_bot cat ~/.ssh/kappmaker_bot.pub
Copy the printed public key.
-
Add the public key to the bot account (browser, logged in as the bot): https://github.com/settings/keys → New SSH key. Optional hardening: if your VPS has a static IP, prefix the key with
from="1.2.3.4"so it only works from that IP. -
Tell SSH to use this key for github.com (on the VPS):
cat >> ~/.ssh/config <<'EOF' Host github.com HostName github.com User git IdentityFile ~/.ssh/kappmaker_bot IdentitiesOnly yes EOF chmod 600 ~/.ssh/config
-
Set the git identity so commits are attributed to the bot, not
root@vps:git config --global user.name "KAppMaker Bot" git config --global user.email "you+kappmakerbot@gmail.com"
-
Verify:
ssh -T git@github.com # → "Hi kappmaker-bot! You've successfully authenticated..." -
Now log into
gh(step 7 above) — choose SSH and point at the same key file.ghwill use it for HTTPS API calls and for git push.
| Scenario | With personal creds | With bot account |
|---|---|---|
| VPS gets root-level compromise | Attacker gets all your private repos, can force-push, delete branches | Attacker only gets repos in the KAppMaker org that bot has write to |
| Bot key leaks | Have to rotate personal key (affects all your machines) | Revoke one key on one account, done |
| You stop using the VPS | Need to remember to revoke the key | Just delete the bot account or remove from org |
When kappmaker builds the web target, the output is just static files — but you're on your phone, so the script bundles a preview helper that gives you a public URL via Cloudflare Tunnel.
# After: ./gradlew :webApp:jsBrowserDistribution
preview ~/projects/<app>/MobileApp/webApp/build/dist/js/productionExecutable
# → prints e.g. https://random-words-here.trycloudflare.comOpen the URL on your phone and you're previewing your KMP web build. When you're done:
preview-stop # stop the default-port preview
preview-stop --all # stop everythingClaude knows this workflow — just ask via Telegram: "build webapp for fittracker and send me the preview link" and it'll run the build, start the tunnel, and reply with the URL.
Tunnel notes:
- URL changes every time the tunnel restarts (it's a free Cloudflare quick tunnel — no account needed)
- Tunnel only lives while
cloudflaredis running on the VPS - For a permanent URL, set up a named Cloudflare Tunnel against your own domain — out of scope here, but the same
cloudflaredbinary supports it
Once paired, message your bot. The kappmaker skill auto-loads when your prompt matches its triggers. Examples:
Create a new app called FitTracker for fitness loggingGenerate a logo for FitTrackerBuild the Android releasePublish to Play Store internal testingBump version to 1.2.0
Memory commands — teach Claude your preferences once, they stick across sessions:
Remember: all new GitHub repos should be privateRemember: use MIT license by defaultWhat do you remember?— Claude shows the contents of~/projects/MEMORY.mdForget the MIT license preference
- iOS builds are not possible on a Linux VPS —
.ipabuilds need macOS/Xcode. App Store Connect metadata setup via kappmaker still works fine; only the actual iOS compile step is unavailable. - Subscription vs. API: Running Claude Code on a VPS is meant for your own interactive use via Telegram, not as a multi-user service or scripted automation pipeline. If you need always-on, multi-user, or scheduled automation, use an Anthropic API key instead.
┌─────────────┐ ┌──────────────────────────┐
│ You (📱) │ ──────► │ Telegram Bot (BotFather)│
└─────────────┘ └────────────┬─────────────┘
│ long-poll
▼
┌──────────────────────────┐
│ VPS (this repo's script)│
│ ┌────────────────────┐ │
│ │ Claude Code │ │
│ │ ├─ telegram plugin│ │
│ │ └─ kappmaker skill│ │
│ └────────────────────┘ │
│ + JDK 17, Android SDK, │
│ Gradle, Node, gh │
└──────────────────────────┘
- Adoptium repo fails on your distro — your Debian/Ubuntu codename may not be in their apt repo yet. Fall back to
sudo apt-get install -y openjdk-17-jdkand adjustJAVA_HOMEto/usr/lib/jvm/java-17-openjdk-${ARCH}. - Android cmdline-tools URL 404s — Google rotates the version number. Get the current link from https://developer.android.com/studio#command-line-tools-only and update
setup-vps.sh. - Telegram bot doesn't respond — check that bot privacy is set to Disable via
@BotFather→/setprivacy, otherwise the bot only sees commands. - Claude can't see plugins after install — restart the
claudesession.