OperateRun under a path
Operate

Run under a path

Serve Turmite under a path of an existing site, such as https://example.com/turmite, behind your own reverse proxy.

Markdown

You can run Turmite beside another app on the same host. Put the path in the site URL. Your own reverse proxy keeps port 443 and the certificate, and passes the path to Turmite.

TURMITE_SITE_URL=https://example.com/turmite

What follows the site URL

Every URL that Turmite makes starts with the site URL:

What URL
Dashboard https://example.com/turmite/dashboard
Invoice page https://example.com/turmite/i/{token}
Payment page https://example.com/turmite/pay/{token}
Merchant API https://example.com/turmite/v1/payment
Static files https://example.com/turmite/assets/
Health check https://example.com/turmite/healthz

Your shop uses https://example.com/turmite as the API base URL.

A project with a checkout domain uses the same path on its own host, for example https://pay.shop-two.com/turmite/pay/{token}.

Install with a path

  1. Run the install script with the full URL and --no-start:

    curl -fsSL https://turmite.com/install.sh | sudo sh -s -- --site-url https://example.com/turmite --no-start

    With a path in the site URL, turmite init sets TURMITE_CADDY_ADDRESS=http://:80 in .env. The bundled Caddy would serve plain HTTP and get no certificate.

  2. Your own proxy already uses ports 80 and 443. Turn off the bundled Caddy and publish the api port on the loopback interface. Write /opt/turmite/docker-compose.override.yml:

    services:
      api:
        ports:
          - "127.0.0.1:8080:8080"
      caddy:
        profiles: [disabled]
  3. Start the stack:

    cd /opt/turmite && sudo docker compose up -d

Docker Compose reads the override file automatically. install.sh --upgrade does not change it.

nginx

Add this to the server block that serves example.com:

location = /turmite { return 301 /turmite/; }

location /turmite/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;
    client_max_body_size 4m;
}

Write proxy_pass without a path. nginx then passes /turmite/... unchanged, and Turmite removes the prefix itself. Turmite also answers requests without the prefix, but the links that it makes always contain the prefix.

Caddy

example.com {
	handle /turmite/* {
		reverse_proxy 127.0.0.1:8080
	}
	# your other app
}

Use handle. Do not use handle_path, because it removes the prefix.

Trusted proxy

The api sees a proxy on the same host at the address of the Docker network gateway. That address is in the default TURMITE_TRUSTED_PROXIES list. If your proxy runs on another machine, set the list. See Client IP addresses.

Cookies and the origin check

  • The session cookie turmite_session has Path=/turmite. Your main app does not receive it.
  • Each dashboard POST must carry an Origin (or Referer) header with the origin of the site URL, here https://example.com. Do not let your proxy change Origin.

Security of a shared host

A path does not separate two apps in the browser. Your main app and Turmite have the same origin. A cross-site scripting bug in the main app lets a script act in the dashboard while an admin is signed in. The cookie path does not stop this.

Turmite still asks for a fresh TOTP code for payouts, API keys and other sensitive actions. Use a path only beside an app that you trust as much as Turmite. In other cases, use a subdomain such as pay.example.com.

Put the dashboard behind your own login

Customers, your shop and the exchange need only these paths:

Path Used by
/turmite/i/ Invoice pages
/turmite/pay/ Payment pages and the status frame
/turmite/x/ Pay with any coin: exchange pages, status frame and the exchange webhook
/turmite/v1/ Your shop's server
/turmite/assets/, /turmite/favicon.svg Checkout styles and images
/turmite/branding/ Project logos
/turmite/healthz Uptime checks

Protect everything else under the prefix. For example, with nginx:

location /turmite/ {
    auth_request /your-admin-auth;
    proxy_pass http://127.0.0.1:8080;
    # the same proxy_set_header lines as above
}

location ~ ^/turmite/(i/|pay/|x/|v1/|assets/|branding/|healthz$|favicon\.svg$) {
    proxy_pass http://127.0.0.1:8080;
    # the same proxy_set_header lines as above
}

nginx uses the regular expression location for the public paths, because it takes priority over the prefix location. Turmite's own login and two-factor checks still apply. For other ways to protect the dashboard, see Private dashboard.