Skip to content

Quick start: Tenantry on your Teleport server in 10 minutes

This is the main path. Tenantry runs on the same server as your Teleport cluster, in Docker. One command starts a guided installer. It finds Teleport, creates what Tenantry needs in it, and asks you only five short groups of questions.

If your Teleport is on another server, or you have no Teleport yet, see Quick start variants.

Before you start

You need:

  • A Linux server with Docker and Docker Compose v2, where Teleport already runs (in a Docker container, or as a local service with its tctl binary).
  • Root access (sudo). The installer hands files to the users of the containers.
  • Teleport 18.x. The Tenantry image embeds tctl 18.11.1, which works with any 18.x cluster. For another major version see Install options.
  • A DNS name for Tenantry, for example tenantry.acme.ch.
  • Decide how people will reach it (the wizard asks). The safe choices:
    • Cloudflare Tunnel + Cloudflare Access: nothing is opened on your firewall. Recommended if you already use Cloudflare.
    • Local network or VPN: the server itself serves HTTPS, with a publicly trusted certificate (TLS certificates).
    • Your own reverse proxy or WAF.

Never expose Tenantry raw to the Internet

Tenantry holds a live Teleport identity and creates roles and tokens. A compromise is a compromise of your cluster. Always put a WAF, Cloudflare Access, a VPN or Teleport in front. See Exposure: never expose raw.

1. Get the installer

git clone https://github.com/Verttigo28/tenantry.git
cd tenantry

2. Run it

sudo scripts/install.sh

With no option, in a terminal, it starts the guided mode. (sudo scripts/install.sh --wizard does the same.) Press Enter to keep the [default]. Nothing is changed before the summary, and Ctrl-C quits.

Step 1/5: Teleport

The installer lists the Teleport it finds on this server, for example On this server: teleport (cluster teleport.acme.ch, Teleport 18.11.4). Choose it.

  • It then asks whether to grant Tenantry's identity the full role. The default (No) is --bot-role minimal: the Steward application and fleet listings, no right to create Teleport roles, join tokens or locks. Yes means --bot-role full (needed by "Add a proxy", the lock button and Tenantry-created roles). Creating roles amounts to cluster administration and a join token can enrol any agent: with the full role, a compromise of Tenantry is a compromise of the cluster. You can change it later by re-running with the other --bot-role.
  • It asks for the public address of the Teleport proxy, for example teleport.acme.ch:443. Agents and tsh use it.

If nothing is detected, it asks for the name of the Teleport container (docker ps). If you answer "Elsewhere", see Quick start variants.

Step 2/5: Public name

The DNS name people open, and a short instance name (the Docker project becomes tenantry-<name>).

Step 3/5: Exposure

Choice What happens
Local network or VPN only This server serves HTTPS itself (Caddy). You get step 4.
Behind my own reverse proxy or WAF Tenantry listens on a private address and port; your proxy terminates TLS. You give the address, the address your proxy connects from (--trust-proxy, so the sign-in rate limit sees real client addresses; printed at the end for a proxy on this server) and the public URL.
Cloudflare Tunnel + Cloudflare Access A cloudflared container opens an outbound tunnel. No port is published. You paste the tunnel token (typed hidden).

Step 4/5: TLS certificate (local network or VPN only)

Because Teleport usually owns port 443, the wizard proposes another HTTPS port (9443) and the public URL becomes https://tenantry.acme.ch:9443.

  • Reachable from the Internet on port 80? Answer yes for HTTP-01.
  • Otherwise choose Let's Encrypt through DNS-01 and pick your DNS provider from the list (Infomaniak, OVHcloud, Cloudflare, Gandi LiveDNS, Hetzner, AWS Route 53, Azure DNS, deSEC, DigitalOcean, Linode/Akamai, PowerDNS, or any other acme.sh provider). It asks for the provider's settings and then the API credentials, typed hidden. See TLS certificates.
  • Or give your own certificate files, your own ACME server, or (lab only) a self-signed certificate.

With a Cloudflare Tunnel or your own proxy this step is skipped: the certificate users see is served by Cloudflare or by your proxy.

Step 5/5: Administrator

A login name (default admin), optionally Teleport single sign-on (issuer, audience, allowed roles and, explicitly, the administrators' role, default tenantry-admin: see Teleport SSO), an installation directory (default /opt/tenantry) and the Tenantry release (default: the version of this checkout; build builds it locally). A strong password is generated and shown once at the end.

Summary and install

The installer prints the equivalent non-interactive command, with secrets as files at placeholder paths (/root/tenantry-dns.env, /root/tenantry-tunnel-token, /root/tenantry-bot-token). Answer y to install. The same command is printed again at the end: keep it for automation, after putting the secrets in those files (mode 0600).

What the installer does

With a local Teleport it uses that Teleport's own tctl, so there is no manual tctl step:

  1. Creates the Teleport roles tenantry (minimal by default), steward-admin and steward-helpdesk (the Steward console roles, so Tenantry never needs to create roles itself) and the Machine ID bot tenantry. The role texts are part of install.sh itself and are sent to tctl on stdin.
  2. Writes the bot join token to a 0400 file, hands it to the tbot container, and deletes it after the first join. From then on tbot renews a short-lived identity (1 hour, renewed every 20 minutes) that Tenantry reads.
  3. Derives the rest from your Teleport: the auth address (<container>:3025, pinned with the cluster CA pins), the Teleport version, the proxy address and, for a container, its Docker network.
  4. Pulls the Tenantry release given with --version (never an implicit latest), pins it by digest and verifies its signature when cosign is installed (--require-signature makes that mandatory), generates the secrets (kept across re-runs), starts the containers and waits for health.

Everything lives in /opt/tenantry/<name> (compose project tenantry-<name>).

First sign-in

Open the public URL and sign in with the administrator login and the password printed at the end.

The Security page should show "Renewed by Machine ID". The Client proxies page should list your agents.

Equivalent command, written out

Guided mode answers like "this server, Cloudflare Tunnel" produce:

sudo scripts/install.sh --name tenantry --public-url https://tenantry.acme.ch \
  --teleport-local docker:teleport --proxy teleport.acme.ch:443 \
  --expose cloudflare-tunnel --tunnel-token-file /root/tenantry-tunnel-token --version <x.y.z>

And "this server, local network, DNS-01 (example provider: Cloudflare DNS)":

sudo scripts/install.sh --name tenantry --public-url https://tenantry.acme.ch:9443 \
  --teleport-local docker:teleport --proxy teleport.acme.ch:443 \
  --tls acme-dns --dns-provider dns_cf --dns-setting CF_Zone_ID=<zone-id> \
  --dns-credentials-file /root/tenantry-dns.env --https-port 9443 --version <x.y.z>

If you chose Cloudflare Tunnel: finish in Cloudflare

At the end the installer prints the three steps. In short:

  1. Create the tunnel first (Cloudflare Zero Trust, Networks, Tunnels, Create a tunnel, cloudflared, Docker) and copy the token: the long string after --token.
  2. Access application first: Access, Applications, Add, Self-hosted. Domain = your Tenantry name. Policy Allow for your MSP team, with MFA, session 8 hours or less.
  3. Public hostname of the tunnel: your Tenantry name, service HTTP tenantry:8443.
  4. Bypass application for the two paths called by client servers without a browser: tenantry.acme.ch/api/callback and tenantry.acme.ch/api/i, policy Bypass (or Allow by the client sites' egress IPs). These endpoints answer only to one-time, unguessable ids.

Do the Access application before the public hostname: until it exists, the name is public. Details and the Teleport side: Exposure: never expose raw.

Next steps

  1. Add your first client: Onboard a client.
  2. Create technicians with a scope per client: Technicians.
  3. Add an alert channel (webhook, ntfy, Teams, Slack): Alerts.
  4. Read Security and the backup page.

Something failed? See Troubleshooting.