Deploying

In production, a Sluurp app is one binary, one app folder and one data folder on a machine you control. No database server, no build step.

In one click

Start from SluurpHQ/starter, a template with a small app and everything a host needs. Each option below keeps your data on a disk of its own, so it survives a redeploy. For commercial use, set your licence as SLUURP_LICENSE.

  • Render: the template’s Deploy to Render button, with a 1 GB disk.
  • Railway: a project from the template, plus a volume at /data.
  • Fly.io: fly launch, a volume named data, then fly deploy.
  • DigitalOcean, Hetzner or any Ubuntu or Debian server: paste cloud-init.yaml as the server’s user data when you create it. Fill in your domain, the first admin and your licence first. On DigitalOcean that’s Create Droplet, Advanced options; on Hetzner Cloud it’s the Cloud config field. Sluurp runs as a service behind Caddy, with HTTPS.

Docker

docker run -d -p 8090:8090 -v sluurp-data:/data -v "$PWD/app:/app" ghcr.io/sluurphq/sluurp

The image serves the app in /app and keeps its data in /data. To ship your app inside it:

FROM ghcr.io/sluurphq/sluurp
COPY --chown=sluurp app /app

On the server

Install the binary, copy the app, and create an admin:

curl -fsSL https://raw.githubusercontent.com/SluurpHQ/releases/main/install.sh | sh
sluurp --dir /srv/sluurp/data superuser you@example.com a-long-password
sluurp --dir /srv/sluurp/data serve --public /srv/sluurp/app --no-hot-reload
  • --dir is the data folder: one SQLite file per project. It’s the only folder you need to back up.
  • --no-hot-reload turns off file watching, which production doesn’t need.
  • --public can also be the app’s repository URL: it’s cloned on first start and pulled on each restart.

Sluurp listens on 127.0.0.1:8090 (local only). Use --addr 0.0.0.0:8090 to accept outside connections, or better, put a reverse proxy in front.

HTTPS

Sluurp serves plain HTTP; a reverse proxy adds HTTPS. Caddy obtains and renews certificates automatically:

school.example.com {
  reverse_proxy 127.0.0.1:8090
}

Realtime, sync and cursors use WebSockets, which Caddy proxies out of the box. With nginx, forward the Upgrade and Connection headers.

Running as a service

A systemd unit that starts Sluurp at boot and restarts it on failure:

/etc/systemd/system/sluurp.service
[Unit]
Description=Sluurp
After=network.target

[Service]
ExecStart=/home/sluurp/.sluurp/bin/sluurp --dir /srv/sluurp/data serve --public /srv/sluurp/app --no-hot-reload
User=sluurp
Restart=always
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now sluurp

Storage

Everything Sluurp keeps is in one folder, the data folder: --dir, or /data in the Docker image.

_system.db, default.db, one .db per projectThe databases: your records, users, settings, pages, and the files server code keeps.
storage/Files people upload, a folder per project. Usually the biggest part.
snapshots/Backups, when you make them here.
logs/Request logs older than a week, one gzipped file a day.
bundles/Production bundles of your app, made at start. They can be made again.

Backups in the admin copy the databases only. Back up storage/ (or the SLUURP_FILES folder) as well, with your usual tools, or keep files in a bucket, below.

Files on a disk of their own

Uploads often outgrow the databases many times over. To keep them on another disk or volume, set SLUURP_FILES to a folder there:

SLUURP_FILES=/mnt/files sluurp --dir /srv/sluurp/data serve --public /srv/sluurp/app

With Docker, mount a volume for them. Either mount it where the files already go:

docker run -d -p 8090:8090 \
  -v sluurp-data:/data \
  -v /mnt/big-disk/sluurp:/data/storage \
  -v "$PWD/app:/app" ghcr.io/sluurphq/sluurp

or mount it anywhere and say where:

docker run -d -p 8090:8090 -e SLUURP_FILES=/files \
  -v sluurp-data:/data -v sluurp-files:/files \
  -v "$PWD/app:/app" ghcr.io/sluurphq/sluurp

When you move existing files, stop Sluurp, copy the storage/ folder to the new place, then start it with the new setting.

The admin shows where the files are, and how much room is left on that disk, under Settings, Storage. The same screen sets how much the project, and each person, may upload; see Files.

Files in a bucket

With more than one server, or to keep files off the server, add an S3-compatible bucket: AWS S3, Cloudflare R2, Backblaze B2 or MinIO. Each upload is copied to the bucket, and a server that lacks a file fetches it from there. See Files for the settings.

Many connections

One Sluurp handles tens of thousands of open connections: pages, API calls, live queries over WebSockets. Each one costs a few kilobytes and no thread. The operating system has limits of its own, though, and on Linux the first one is 1,024 open files per process. Every connection is an open file.

Sluurp raises its own limit as far as the system lets it when it starts. The LimitNOFILE line in the unit above lets it go that far. The server install script also sets these, and you can set them yourself on any Linux server:

/etc/sysctl.d/90-sluurp.conf
net.core.somaxconn = 8192
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
fs.file-max = 2097152
sudo sysctl --system

They make room for a burst of new connections, give requests your functions make to other services all the local ports, and reuse closed sockets sooner. With Docker, pass --ulimit nofile=1048576:1048576 to docker run.

If Caddy or nginx sits in front, it holds a connection to each client and one to Sluurp, so give it the same limit.

Backups

sluurp backup writes a dated snapshot of every project to snapshots/ in the data folder. Backups in the admin UI schedules them and sets how many to keep. Copy snapshots off the machine too: a backup on the same disk won’t survive that disk.

Upgrades

Replace the binary and restart. On startup Sluurp upgrades its own tables and runs any pending app migrations. Back up first; sluurp migrate APP --plan shows what will run.

No server at all

A site that doesn’t need the API, sync or server functions (a landing page, docs) can be exported as static files with sluurp static and hosted on GitHub Pages or any file host.