Deploy with Docker

Host Sugabots on a server or a hosting platform so your team can use it.

The Quickstart runs Sugabots on your own computer. To use it with other people, host it somewhere they can reach over HTTPS, and set up email so they receive their invites.

Sugabots is a single Docker image, ghcr.io/nitrictech/sugabots, that serves both the web app and the API. It stores everything in PostgreSQL 18.

Requirements

  • A Linux server with Docker and Docker Compose, or a hosting platform that runs Docker images
  • A domain name, such as sugabots.example.com, pointed at the server
  • An email provider, such as Resend

On your own server

  1. Create compose.yml

    Make a folder for Sugabots, and save this in it as compose.yml. Replace sugabots.example.com with your domain, and example.com in the sender with the domain you'll send email from.

    compose.yml
    name: sugabots
    
    services:
      sugabots:
        image: ghcr.io/nitrictech/sugabots:latest
        ports:
          - "3000:3000"
        environment:
          DATABASE_URL: postgres://sugabots:${POSTGRES_PASSWORD}@postgres:5432/sugabots
          PUBLIC_URL: https://sugabots.example.com
          BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:?Set it in .env}
          CREDENTIALS_ENCRYPTION_KEY: ${CREDENTIALS_ENCRYPTION_KEY:?Set it in .env}
          EMAIL_PROVIDER: resend
          EMAIL_RESEND_API_KEY: ${EMAIL_RESEND_API_KEY:?Set it in .env}
          EMAIL_TRANSACTIONAL_FROM: Sugabots <no-reply@example.com>
        depends_on:
          postgres:
            condition: service_healthy
        restart: unless-stopped
    
      postgres:
        image: postgres:18-alpine
        environment:
          POSTGRES_USER: sugabots
          POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set it in .env}
          POSTGRES_DB: sugabots
        volumes:
          - postgres_data:/var/lib/postgresql
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U sugabots -d sugabots"]
          interval: 5s
          retries: 12
        restart: unless-stopped
    
    volumes:
      postgres_data:

    PUBLIC_URL must be the address people see in their browser: links in emails and sign-in redirects are built from it. Every other setting is in the configuration reference.

    To keep files on a volume rather than in the database, add those settings now, before anyone uses Sugabots.

  2. Create .env

    In the same folder, generate the database password and the two secret keys:

    Terminal
    echo "POSTGRES_PASSWORD=$(openssl rand -hex 32)" >> .env
    echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)" >> .env
    echo "CREDENTIALS_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> .env

    Then add your Resend API key. If you don't have one yet, follow Resend to get one:

    .env
    EMAIL_RESEND_API_KEY=re_your_api_key
  3. Start Sugabots

    Terminal
    docker compose up -d

    Sugabots sets up its database on the first start. Check that it's running with docker compose logs sugabots.

  4. Add HTTPS

    Sugabots serves plain HTTP on port 3000. Put a reverse proxy in front of it to serve HTTPS. With Caddy, which gets and renews certificates automatically, add this to /etc/caddy/Caddyfile:

    /etc/caddy/Caddyfile
    sugabots.example.com {
    	reverse_proxy 127.0.0.1:3000
    }

    Then reload Caddy:

    Terminal
    sudo systemctl reload caddy

    Your domain's DNS must already point at the server for Caddy to get a certificate.

    Another reverse proxy works too, as long as it:

    • passes WebSocket connections, which a bot's live desktop uses
    • accepts uploads up to 30 MB, the largest file people can attach

    Caddy does both by default. nginx does neither until it's told to: without these settings, a bot's desktop never connects, and most phone photos are refused as too large. Add this to /etc/nginx/sites-available/sugabots, and link it into /etc/nginx/sites-enabled/:

    /etc/nginx/sites-available/sugabots
    map $http_upgrade $connection_upgrade {
    	default upgrade;
    	''      close;
    }
    
    server {
    	listen 80;
    	server_name sugabots.example.com;
    	# Room for a 30 MB attachment. nginx's default is 1 MB.
    	client_max_body_size 32m;
    
    	location / {
    		proxy_pass http://127.0.0.1:3000;
    		proxy_http_version 1.1;
    		# Passes WebSocket connections on to Sugabots.
    		proxy_set_header Upgrade $http_upgrade;
    		proxy_set_header Connection $connection_upgrade;
    		proxy_set_header Host $host;
    	}
    }

    Check the configuration and reload nginx, then add HTTPS with Certbot, which adds the certificate to this server block:

    Terminal
    sudo nginx -t && sudo systemctl reload nginx
    sudo certbot --nginx -d sugabots.example.com
  5. Create your account

    Open https://sugabots.example.com and sign up. A new installation lets its first account in without an invitation, and you own the workspace you create.

On a hosting platform

Platforms such as Suga, Railway and Render can run the image and provide HTTPS.

On Suga, the Sugabots template creates the service and its PostgreSQL 18 database for you. On other platforms, create a PostgreSQL 18 database, then a service from ghcr.io/nitrictech/sugabots:latest.

Either way, the service needs these settings:

  • DATABASE_URL: the database's connection string
  • PUBLIC_URL: the service's HTTPS address
  • BETTER_AUTH_SECRET and CREDENTIALS_ENCRYPTION_KEY: generate each with openssl rand -base64 32
  • The email settings from compose.yml above: EMAIL_PROVIDER, EMAIL_RESEND_API_KEY and EMAIL_TRANSACTIONAL_FROM

See the configuration reference for what each does.

Files on a volume

Sugabots keeps files, such as attachments and large tool results, in the database unless told otherwise. There, every file adds to the database and its backups, and each one is held in memory while it's saved. To keep them on a volume instead, add these settings and a files volume to compose.yml, keeping what's already there:

compose.yml
services:
  sugabots:
    environment:
      BLOB_STORE_PROVIDER: filesystem
      BLOB_STORE_FILESYSTEM_ROOT: /data/files
    volumes:
      - files:/data/files

volumes:
  postgres_data:
  files:

Add both: without the volume, files are lost when the container is replaced, such as when you update. Then run docker compose up -d. The compose.yml the Quickstart downloads has these lines, commented out.

Choose before you start using Sugabots. Files already kept stay in the database, and Sugabots can't open them unless you switch back.

To keep files in a folder on the server rather than a Docker volume, make the folder and give it to the user Sugabots runs as:

Terminal
sudo mkdir -p /srv/sugabots/files
sudo chown 1000:1000 /srv/sugabots/files

Keep the two settings, but mount the folder in place of files:/data/files, and leave out files: at the end:

compose.yml
services:
  sugabots:
    volumes:
      - /srv/sugabots/files:/data/files

If Sugabots can't write to the folder, it stops, and docker compose logs sugabots says why.

On a hosting platform, attach a persistent disk at /data/files, set the same two settings, and run one copy of the service: the disk belongs to one server. Without a disk, keep the default: files kept in the container are lost when it's replaced.

Email

Sugabots sends email for invites and address verification. Without a provider, emails are only printed to the logs, and you have to send people their links yourself.

Resend

  1. Verify your domain

    Create a Resend account. Under Domains, add the domain you'll send from, add the DNS records Resend shows you, and wait for the domain to be verified.

  2. Create an API key

    Under API Keys, create a key with Sending access.

  3. Configure Sugabots

    Put the key in .env as EMAIL_RESEND_API_KEY, and set EMAIL_TRANSACTIONAL_FROM in compose.yml to an address on the domain you verified. Then restart with docker compose up -d, and invite someone from Settings → Members to check that email arrives.

Other providers

To send through another provider, point Sugabots at a small service of your own that passes each email on. See the webhook settings in the configuration reference.

Resend is the first provider built in, and more are on the way. Each one is a short module in the Sugabots repository, so if yours isn't supported yet, adding it is a welcome contribution.

Sandboxes

To run your bots' sandboxes on your own server with Docker, the server needs Linux 5.9 or later. Check which version it runs with:

Terminal
uname -r

On an older version, sandboxes start and bots can run commands in them, but nothing opens from the dock on a sandbox's desktop: its apps bounce and never appear. Ubuntu 20.04, for example, comes with 5.4. Install a newer kernel, or a newer release of your operating system, and restart the server.

What OpenSandbox can see

OpenSandbox adds your connections' credentials to a sandbox's requests as they leave it. For secure (HTTPS) connections, it decrypts each one beside the sandbox, adds the credentials, and encrypts it again before it goes on to the site. So OpenSandbox can read the sandbox's connections, the browser's on its desktop included, and whoever runs your OpenSandbox can see what's sent through them, such as a password typed into a site.

If you run OpenSandbox yourself, that's you. Otherwise, choose someone you'd trust with it.

Updating

Back up first, then pull the new image and restart:

Terminal
docker compose pull
docker compose up -d

Sugabots applies any database migrations when it starts.

To try changes before they're released, use ghcr.io/nitrictech/sugabots:edge instead of :latest. It's rebuilt each time the main branch changes, so it can break. Each build is also tagged sha- and its commit, such as sha-a1b2c3d, if you want to stay on one.

Backups

Back up two things: the database, and the .env file holding the keys. Keep them together: without its keys, a restored database can't read its saved API keys, and everyone has to sign in again.

To write the database to a file:

Terminal
docker compose exec -T postgres pg_dump -U sugabots sugabots > sugabots-backup.sql

To restore, put the .env from the same backup beside compose.yml. Then stop Sugabots, replace the database with an empty one, load the backup, and start Sugabots again:

Terminal
docker compose stop sugabots
docker compose exec -T postgres dropdb -U sugabots sugabots
docker compose exec -T postgres createdb -U sugabots sugabots
docker compose exec -T postgres psql -U sugabots -d sugabots < sugabots-backup.sql
docker compose start sugabots

This deletes whatever is in the database before loading the backup. If the backup is from an older version, Sugabots applies the newer migrations when it starts.

If you keep files on a volume, back it up after the database, and restore it from the same backup: the database lists the files, and the volume holds them. In the same folder, write the volume to a file:

Terminal
docker run --rm -v sugabots_files:/data/files -v "$PWD":/backup alpine \
  tar czf /backup/sugabots-files.tar.gz -C /data/files .

To restore it, run this before docker compose start sugabots above:

Terminal
docker run --rm -v sugabots_files:/data/files -v "$PWD":/backup alpine \
  tar xzf /backup/sugabots-files.tar.gz -C /data/files

For a folder on the server, archive the folder itself instead.

On a hosting platform, use the platform's database backups, and its disk backups if you keep files on a disk. Keep a copy of the two keys too.

Building the image yourself

To run your own changes, build the image from a checkout of the repository and use it in place of ghcr.io/nitrictech/sugabots:latest:

Terminal
docker build -t sugabots .