Skip to content

Instantly share code, notes, and snippets.

@pojntfx
Last active April 9, 2026 07:38
Show Gist options
  • Select an option

  • Save pojntfx/5916ceb7ec35eb010010400447e9c034 to your computer and use it in GitHub Desktop.

Select an option

Save pojntfx/5916ceb7ec35eb010010400447e9c034 to your computer and use it in GitHub Desktop.
Set up Nanobot with OpenRouter and Ollama

You need SSH access, a personal Matrix account, a bot Matrix account, and a server (if self-hosting via Ollama, at least 32 GB of RAM)

1. Clean Up Old Matrix Sessions

Sign into your bot account in Element, go to Settings → Sessions, and delete any stale sessions to avoid E2EE key conflicts.

2. Create the Service User

SSH into the server and create a dedicated nanobot user with passwordless sudo and lingering enabled (so its systemd user services survive logout):

ssh root@<SERVER_IP>

useradd -m nanobot
echo "nanobot ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/nanobot
passwd -d nanobot
loginctl enable-linger nanobot
su - nanobot

3. Install Dependencies

sudo dnf install -y nodejs npm python3-pip python3-devel cmake gcc-c++ @development-tools jq moreutils

4. Install and Onboard Nanobot

pip install nanobot-ai[matrix]
nanobot onboard

5. Log In to Matrix

You must use a new device_id every time you re-register the bot.

Create a temporary login payload and authenticate against the Matrix homeserver:

cat > /tmp/login.json << 'EOF'
{
  "type": "m.login.password",
  "identifier": {
    "type": "m.id.user",
    "user": "<BOT_MATRIX_ID>"
  },
  "password": "<BOT_PASSWORD>",
  "device_id": "<DEVICE_ID>",
  "initial_device_display_name": "<DEVICE_DISPLAY_NAME>"
}
EOF

curl -s -X POST "https://matrix.org/_matrix/client/v3/login" \
  -H "Content-Type: application/json" \
  -d @/tmp/login.json | jq .

6. Configure the Matrix Channel

Inject the Matrix channel config into Nanobot and clean up the login payload and any stale sync state:

rm -f /tmp/login.json && jq '.channels.matrix = {
  "enabled": true,
  "homeserver": "https://matrix.org",
  "accessToken": "<ACCESS_TOKEN>",
  "userId": "<BOT_MATRIX_ID>",
  "deviceId": "<DEVICE_ID>",
  "e2eeEnabled": true,
  "syncStopGraceSeconds": 2,
  "maxMediaBytes": 20971520,
  "allowFrom": ["<YOUR_MATRIX_ID>"],
  "groupPolicy": "allowlist",
  "groupAllowFrom": ["<YOUR_MATRIX_ID>"],
  "allowRoomMentions": false
}' ~/.nanobot/config.json | sponge ~/.nanobot/config.json

rm -f ~/.nanobot/matrix-store/<BOT_MATRIX_ID>_*.db

7. Configure the LLM Provider

Option A: OpenRouter

Set the OpenRouter API key and select a model:

jq '.providers.openrouter.apiKey = "<OPENROUTER_API_KEY>" | .agents.defaults.provider = "openrouter"' \
  ~/.nanobot/config.json | sponge ~/.nanobot/config.json

jq '.agents.defaults.model = "qwen/qwen3.6-plus:free"' \
  ~/.nanobot/config.json | sponge ~/.nanobot/config.json

Models that work well on OpenRouter:

Model Self-hostable Price
qwen/qwen3.6-plus No $0.33 / 1M tokens
xiaomi/mimo-v2-pro No $1.00 / 1M tokens
minimax/minimax-m2.7 No $0.30 / 1M tokens
qwen/qwen3.5-27b Yes (qwen3.5:27b) $0.19 / 1M tokens
google/gemma-4-26b-a4b-it Yes (gemma4:26b) $0.13 / 1M tokens

Option B: Local Ollama

Install Ollama, point Nanobot at it, and select a model:

curl -fsSL https://ollama.com/install.sh | sh

jq '.providers.ollama.apiBase = "http://localhost:11434/v1" | .agents.defaults.provider = "ollama"' \
  ~/.nanobot/config.json | sponge ~/.nanobot/config.json

jq '.agents.defaults.model = "gemma4:26b"' \
  ~/.nanobot/config.json | sponge ~/.nanobot/config.json

8. Verify the Device (E2EE)

Start the gateway temporarily so the device registers its keys:

nanobot gateway

From another terminal, query the device's public keys:

ssh root@<SERVER_IP>

curl -s -X POST "https://matrix.org/_matrix/client/v3/keys/query" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"device_keys":{"<BOT_MATRIX_ID>":["<DEVICE_ID>"]}}' \
  | jq '{keys: .device_keys["<BOT_MATRIX_ID>"]["<DEVICE_ID>"].keys, sigs: .device_keys["<BOT_MATRIX_ID>"]["<DEVICE_ID>"].signatures}'

Note down the ed25519 fingerprint from the output.

Next, add your bot account on your Matrix client and send "Hi" - the bot won't respond yet because the device is unverified.

Sign into your bot account in Element, open the new chat containing "Hi", and run:

/verify <DEVICE_ID> <ED25519_FINGERPRINT>

Go to Settings → Sessions and confirm the bot session is now verified.

Back in your Matrix client, send "Hi" again — the bot should now respond.

9. Set Up the Systemd Service

Stop the temporary nanobot gateway process, then create a persistent user service:

mkdir -p ~/.config/systemd/user

cat > ~/.config/systemd/user/nanobot-gateway.service << 'EOF'
[Unit]
Description=Nanobot Gateway
After=network.target

[Service]
Type=simple
ExecStart=%h/.local/bin/nanobot gateway
Restart=always
RestartSec=10
Environment=PATH=%h/.local/bin:/usr/local/bin:/usr/bin:/bin

[Install]
WantedBy=default.target
EOF

export XDG_RUNTIME_DIR=/run/user/$(id -u)
export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus

systemctl --user daemon-reload
systemctl --user enable --now nanobot-gateway

Verify it's running:

systemctl --user status nanobot-gateway
journalctl --user -u nanobot-gateway -f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment