# Deployment ## Docker > [!TIP] > The `-v ~/.nanobot:/home/nanobot/.nanobot` flag mounts your local config directory into the container, so your config and workspace persist across container restarts. > The container runs as user `nanobot` (UID 1000). If you get **Permission denied**, fix ownership on the host first: `sudo chown -R 1000:1000 ~/.nanobot`, or pass `--user $(id -u):$(id -g)` to match your host UID. Podman users can use `--userns=keep-id` instead. ### Docker Compose ```bash docker compose run --rm nanobot-cli onboard # first-time setup vim ~/.nanobot/config.json # add API keys docker compose up -d nanobot-gateway # start gateway ``` ```bash docker compose run --rm nanobot-cli agent -m "Hello!" # run CLI docker compose logs -f nanobot-gateway # view logs docker compose down # stop ``` ### Docker ```bash # Build the image docker build -t nanobot . # Initialize config (first time only) docker run -v ~/.nanobot:/home/nanobot/.nanobot --rm nanobot onboard # Edit config on host to add API keys vim ~/.nanobot/config.json # Run gateway (connects to enabled channels, e.g. Telegram/Discord/Mochat) docker run -v ~/.nanobot:/home/nanobot/.nanobot -p 18790:18790 nanobot gateway # Or run a single command docker run -v ~/.nanobot:/home/nanobot/.nanobot --rm nanobot agent -m "Hello!" docker run -v ~/.nanobot:/home/nanobot/.nanobot --rm nanobot status ``` ## Linux Service Run the gateway as a systemd user service so it starts automatically and restarts on failure. **1. Find the nanobot binary path:** ```bash which nanobot # e.g. /home/user/.local/bin/nanobot ``` **2. Create the service file** at `~/.config/systemd/user/nanobot-gateway.service` (replace `ExecStart` path if needed): ```ini [Unit] Description=Nanobot Gateway After=network.target [Service] Type=simple ExecStart=%h/.local/bin/nanobot gateway Restart=always RestartSec=10 NoNewPrivileges=yes ProtectSystem=strict ReadWritePaths=%h [Install] WantedBy=default.target ``` **3. Enable and start:** ```bash systemctl --user daemon-reload systemctl --user enable --now nanobot-gateway ``` **Common operations:** ```bash systemctl --user status nanobot-gateway # check status systemctl --user restart nanobot-gateway # restart after config changes journalctl --user -u nanobot-gateway -f # follow logs ``` If you edit the `.service` file itself, run `systemctl --user daemon-reload` before restarting. > **Note:** User services only run while you are logged in. To keep the gateway running after logout, enable lingering: > > ```bash > loginctl enable-linger $USER > ``` ## macOS LaunchAgent On macOS, run the gateway as a `launchd` user agent so it starts automatically after login and restarts if it exits unexpectedly. **1. Find the nanobot binary path:** ```bash which nanobot # e.g. /Users/youruser/.local/bin/nanobot ``` Use this absolute `nanobot` path in `ProgramArguments` so the console script keeps the Python environment from your install method. **2. Create the LaunchAgent plist** at `~/Library/LaunchAgents/ai.nanobot.gateway.plist` (replace paths if needed): ```xml Label ai.nanobot.gateway ProgramArguments /Users/youruser/.local/bin/nanobot gateway --workspace /Users/youruser/.nanobot/workspace WorkingDirectory /Users/youruser/.nanobot/workspace RunAtLoad KeepAlive SuccessfulExit StandardOutPath /Users/youruser/.nanobot/logs/gateway.log StandardErrorPath /Users/youruser/.nanobot/logs/gateway.error.log EnvironmentVariables PATH /Users/youruser/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin PYTHONUNBUFFERED 1 ``` **3. Load and start it:** ```bash mkdir -p ~/.nanobot/logs launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.nanobot.gateway.plist launchctl enable gui/$(id -u)/ai.nanobot.gateway launchctl kickstart -k gui/$(id -u)/ai.nanobot.gateway ``` **Common operations:** ```bash launchctl list | grep ai.nanobot.gateway launchctl kickstart -k gui/$(id -u)/ai.nanobot.gateway launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/ai.nanobot.gateway.plist log stream --process nanobot ``` If you edit the plist itself, run `launchctl bootout ...` and `launchctl bootstrap ...` again so `launchd` reloads the updated definition. > **Note:** if `launchctl kickstart` fails with an "address already in use" error, you probably still have a manually started `nanobot gateway` process running on the same port. Stop the manual process first, then kickstart the LaunchAgent again.