# Self-host with Docker

> Run Crewtavo on your own computer or server with Docker and one command. The same five services as on Railway, with your data in Docker volumes.

Crewtavo runs anywhere Docker does: a laptop, an office server or a rented server (VPS). It's the same five services the Railway template creates. This page is for whoever looks after the server; most businesses are better off [on Railway](https://crewtavo.com/docs/getting-started/set-up-on-railway/).

## What you need

- [Docker](https://docs.docker.com/get-docker/)
- [Node.js](https://nodejs.org) 20 or newer, only to generate the secrets and start Docker

## Start it

```bash
git clone https://github.com/jviars/crewtavo.git
cd crewtavo
npm run instance
```

The first run writes `.env.instance` with new secrets, builds Crewtavo, starts everything and prints the address: `http://localhost:8080`. Open it and [create the owner account](https://crewtavo.com/docs/getting-started/first-sign-in/).

:::danger[Keep .env.instance]
The database is locked with the secrets in `.env.instance`. Without that file, your data can't be opened.
:::

## Day to day

```bash
npm run instance -- logs                           # follow what's happening
npm run instance -- stop                           # stop it; the data stays in Docker volumes
npm run instance                                   # start again, or update after a git pull
docker compose --env-file .env.instance down -v    # delete the instance and all its data
```

To update, run `git pull` in the Crewtavo folder, then `npm run instance` again.

## On a server with your own domain

**Settings → Web address** walks you through these steps with your domain filled in, and checks each one.

1. Point a DNS record for your domain (say `ops.example.com`) at the server.
2. In `.env.instance`, set `APP_URL=https://ops.example.com`, then run `npm run instance` again.
3. Put a web server with HTTPS in front of port 8080, on the same server. With [Caddy](https://caddyserver.com), this whole `Caddyfile` gets a certificate and forwards everything:

```
ops.example.com {
  reverse_proxy localhost:8080
}
```

Port 8080 only answers on the server itself (`CREWTAVO_BIND`, `127.0.0.1` by default), so visitors come in through the web server.

## Visitors' addresses

Public pages (booking forms, promo codes, Client Hub payments and messages, sign-in links, the first-run setup) limit how often each visitor can use them, by the visitor's address. Crewtavo only trusts the address its own proxy sets:

- **Caddy** adds each visitor's address to `X-Forwarded-For`, which is what Crewtavo reads. Nothing to change.
- **nginx** needs `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`.
- **A web server on another machine:** set `CREWTAVO_BIND` to this server's address on the private network between them, not `0.0.0.0`.
- **No web server**, trying Crewtavo from other computers on your network: set `CREWTAVO_BIND=0.0.0.0` and `CREWTAVO_VISITOR_IP=connection`.
- **Something else in front**, like Cloudflare's proxy before Caddy: set `CREWTAVO_VISITOR_IP`. See [Behind other proxies](https://crewtavo.com/docs/hosting/settings/#behind-other-proxies).

## Backups

Back up the `crewtavo-instance_db-data` and `crewtavo-instance_storage-data` Docker volumes, and `.env.instance`. See [Back up and export your data](https://crewtavo.com/docs/hosting/backups/).

## Optional features

Texting, online payments, maps, AI and accounting each take a key or two in `.env.instance`. See [Optional settings](https://crewtavo.com/docs/hosting/settings/).

Source: https://crewtavo.com/docs/hosting/docker/ (last updated 2026-10-18)
