Maincloud is now LIVE! Get Maincloud Energy 90% off until we run out!

Self Hosting SpacetimeDB

This tutorial will guide you through setting up SpacetimeDB on an Ubuntu 24.04 server, securing it with HTTPS using Nginx and Let's Encrypt, and configuring a systemd service to keep it running.

Prerequisites

  • A fresh Ubuntu 24.04 server (VM or cloud instance of your choice)
  • A domain name (e.g., example.com)
  • sudo privileges on the server

Step 1: Create a Dedicated User for SpacetimeDB

For security purposes, create a dedicated spacetimedb user to run SpacetimeDB:

sudo mkdir /stdb
sudo useradd --system spacetimedb
sudo chown -R spacetimedb:spacetimedb /stdb 

Install SpacetimeDB as the new user:

sudo -u spacetimedb bash -c 'curl -sSf https://install.spacetimedb.com | sh -s -- --root-dir /stdb --yes' 

Step 2: Create a Systemd Service for SpacetimeDB

To ensure SpacetimeDB runs on startup, create a systemd service file:

sudo nano /etc/systemd/system/spacetimedb.service 

Add the following content:

[Unit]
Description=SpacetimeDB Server
After=network.target

[Service]
ExecStart=/stdb/spacetime --root-dir=/stdb start --listen-addr='127.0.0.1:3000'
Restart=always
User=spacetimedb
WorkingDirectory=/stdb

[Install]
WantedBy=multi-user.target 

Enable and start the service:

sudo systemctl enable spacetimedb
sudo systemctl start spacetimedb 

Check the status:

sudo systemctl status spacetimedb 

Step 3: Install and Configure Nginx

Install Nginx

sudo apt update
sudo apt install nginx -y 

Configure Nginx Reverse Proxy

Create a new Nginx configuration file:

sudo nano /etc/nginx/sites-available/spacetimedb 

Add the following configuration, remember to change example.com to your own domain:

server {
    listen 80;
    server_name example.com;

    #########################################
    # By default SpacetimeDB is completely open so that anyone can publish to it. If you want to block
    # users from creating new databases you should keep this section commented out. Otherwise, if you
    # want to open it up (probably for dev environments) then you can uncomment this section and then
    # also comment out the location / section below.
    #########################################
    # location / {
    #     proxy_pass http://localhost:3000;
    #     proxy_http_version 1.1;
    #     proxy_set_header Upgrade $http_upgrade;
    #     proxy_set_header Connection "Upgrade";
    #     proxy_set_header Host $host;
    # }

    # Anyone can subscribe to any database.
    # Note: This is the only section *required* for the websocket to function properly. Clients will
    # be able to create identities, call reducers, and subscribe to tables through this websocket.
    location ~ ^/v1/database/[^/]+/subscribe$ {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }

    # Uncomment this section to allow all HTTP reducer calls
    # location ~ ^/v1/[^/]+/call/[^/]+$ {
    #     proxy_pass http://localhost:3000;
    #     proxy_http_version 1.1;
    #     proxy_set_header Upgrade $http_upgrade;
    #     proxy_set_header Connection "Upgrade";
    #     proxy_set_header Host $host;
    # }

    # Uncomment this section to allow all HTTP sql requests
    # location ~ ^/v1/[^/]+/sql$ {
    #     proxy_pass http://localhost:3000;
    #     proxy_http_version 1.1;
    #     proxy_set_header Upgrade $http_upgrade;
    #     proxy_set_header Connection "Upgrade";
    #     proxy_set_header Host $host;
    # }

    # NOTE: This is required for the typescript sdk to function, it is optional
    # for the rust and the C# SDKs.
    location /v1/identity {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }

    # Block all other routes explicitly. Only localhost can use these routes. If you want to open your
    # server up so that anyone can publish to it you should comment this section out.
    location / {
        allow 127.0.0.1;
        deny all;
    }
} 

This configuration by default blocks all connections other than /v1/identity and /v1/database/<database-name>/subscribe which only allows the most basic functionality. This will prevent all remote users from publishing to your SpacetimeDB instance.

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/spacetimedb /etc/nginx/sites-enabled/ 

Restart Nginx:

sudo systemctl restart nginx 

Configure Firewall

Ensure your firewall allows HTTPS traffic:

sudo ufw allow 'Nginx Full'
sudo ufw reload 

Step 4: Secure with Let's Encrypt

Install Certbot

sudo apt install certbot python3-certbot-nginx -y 

Obtain an SSL Certificate

Run this command to request a new SSL cert from Let's Encrypt. Remember to replace example.com with your own domain:

sudo certbot --nginx -d example.com 

Certbot will automatically configure SSL for Nginx. Restart Nginx to apply changes:

sudo systemctl restart nginx 

Auto-Renew SSL Certificates

Certbot automatically installs a renewal timer. Verify that it is active:

sudo systemctl status certbot.timer 

Step 5: Verify Installation

On your local machine, add this new server to your CLI config. Make sure to replace example.com with your own domain:

spacetime server add self-hosted --url https://example.com 

If you have uncommented the /v1/publish restriction in Step 3 then you won't be able to publish to this instance unless you copy your module to the host first and then publish. We recommend something like this:

spacetime build
scp target/wasm32-unknown-unknown/release/spacetime_module.wasm ubuntu@<host>:/home/ubuntu/
ssh ubuntu@<host> spacetime publish -s local --bin-path spacetime_module.wasm <database-name> 

You could put the above commands into a shell script to make publishing to your server easier and faster. It's also possible to integrate a script like this into Github Actions to publish on some event (like a PR merging into master).

Step 6: Updating SpacetimeDB Version

To update SpacetimeDB to the latest version, first stop the service:

sudo systemctl stop spacetimedb 

Then upgrade SpacetimeDB:

sudo -u spacetimedb -i -- spacetime --root-dir=/stdb version upgrade 

To install a specific version, use:

sudo -u spacetimedb -i -- spacetime --root-dir=/stdb install <version-number> 

Finally, restart the service:

sudo systemctl start spacetimedb 

Step 7: Troubleshooting

SpacetimeDB Service Fails to Start

Check the logs for errors:

sudo journalctl -u spacetimedb --no-pager | tail -20 

Verify that the spacetimedb user has the correct permissions:

sudo ls -lah /stdb/spacetime 

If needed, add the executable permission:

sudo chmod +x /stdb/spacetime 

Let's Encrypt Certificate Renewal Issues

Manually renew the certificate and check for errors:

sudo certbot renew --dry-run 

Nginx Fails to Start

Test the configuration:

sudo nginx -t 

If errors are found, check the logs:

sudo journalctl -u nginx --no-pager | tail -20 
Edit On Github