Skip to main content

Install

Two files, a folder, and Docker. The setup builder writes both files for you; you download them, run one command, and you're up. No cloning, no building. The hardware bar is modest: see what you need.

Two ways to start

  • The fast path. Run over plain HTTP and you're using Cobblr in about five minutes. One limitation: scanning from your phone requires HTTPS, so the camera is off until you add it. Adding it later is a two-line edit to the same install; nothing gets redone.
  • Right the first time. If you'd rather never touch it twice, set up Tailscale before you install (roughly 30 minutes if it's new to you), pick Tailscale in the builder instead of HTTP, and you arrive with HTTPS, the phone camera, and remote access on day one.

Both paths are the same two files and the same command. The only difference is the HTTPS choice you make in the builder, and it's never final.

The fast path: install over HTTP

  1. Generate your files. Open the setup builder. Fill in your email, and under the HTTPS choice pick HTTP (no TLS). Set the address to your box's LAN IP and port, like 192.168.1.50:8088. The builder generates every secret for you. Download .env and docker-compose.yml into one folder on the box.

    Back up the encryption key

    The builder makes you confirm you've saved TENANT_CREDS_ENCRYPTION_KEY before the download unlocks. Keep that copy off this box. If you lose it, stored integration credentials can't be recovered.

    Keep data on a NAS or a data disk

    The builder's Advanced section has a Data location field. Set it and every mount (database, uploaded files, installed modules, TLS certs) lands under that one path, so Cobblr's data can live on a NAS mount or an appdata root instead of beside the compose file. Leave it blank to keep ./data. See Configuration.

  2. Bring it up:

    docker compose up -d

    Docker pulls the images (a few minutes the first time) and starts them. Nothing builds.

  3. Open it at http://<your-box-ip>:8088 from any device on your network, or at http://localhost:8088 on the box itself. Create your account (signup is open on first run) and look around.

You now have a working instance, with the one limitation from the fork above:

The phone camera requires HTTPS

Browsers only allow the camera (barcode scanning, photos) over HTTPS or on localhost. Scanning works in the browser on the box at localhost:8088, but not from your phone over http://192.168.x.x. It's a browser rule; nothing in Cobblr overrides it. The next section fixes it in place.

Turn on HTTPS

This section is both the upgrade from the fast path and the first stop on the do-it-right path; the steps call out where the two differ. HTTPS is what the phone camera requires, and depending on the option you pick here, secure remote access can come along with it.

The catch with a home box: a public certificate authority won't issue a certificate for a private IP, and a public name won't reach your box unless you open a port to the internet or run your own DNS. So getting real HTTPS onto your LAN takes one of the approaches below.

We suggest Tailscale. If you don't already have it (or another solution to this problem), it's worth the roughly 30 minutes to set up. It gives you a real certificate with nothing exposed, and as a bonus you can then reach any of your self-hosted things securely from anywhere, not just Cobblr.

Tailscale puts your devices on a private mesh network with real, auto-renewed certificates. Nothing is forwarded, nothing is exposed, and the same URL works at home or away. There are two ways to ride it; the first is easier and gives the nicer URL.

Own hostname (easiest)

Cobblr's bundled proxy joins your tailnet by itself and serves the address you choose: the first part of the address becomes the node's name, so cobblr.<your-tailnet>.ts.net joins as cobblr, shop.<your-tailnet>.ts.net as shop. The box needs no Tailscale install at all; only the devices you browse from do.

  1. Prepare the tailnet (one-time, in the admin console): enable MagicDNS and HTTPS certificates on the DNS page. That page also shows your tailnet name, the tail1234.ts.net part of the address.

  2. Build your files. In the builder, set the address to cobblr.<your-tailnet>.ts.net, pick Tailscale, and keep Own hostname. Leave the join set to Approve in browser (no key). Fresh install: download both files and bring them up as in fast-path step 2. Upgrading from the fast path: add these to your existing .env (keep your secrets) and remove the WEB_BIND line, then docker compose up -d:

    COBBLR_SITE_ADDRESS=cobblr.tail1234.ts.net
    COMPOSE_PROFILES=caddy
    COBBLR_TLS_MODE=tsnet
  3. Approve the box. On first start it asks Tailscale to authorize itself and prints a one-time link in the logs. Grab it with docker compose logs caddy | grep -iE 'to authenticate|login.tailscale', open it, sign in, and approve the new node. This is the same click-to-approve you get authorizing any device, so there is no key to mint.

  4. Open it at your chosen address from any device signed into your tailnet (install the Tailscale app on your phone and laptop). The camera works everywhere now. One follow-up: find the new node in the admin console and disable key expiry on it, or it signs itself out in about six months.

Prefer no link to click?

For a fully unattended box, mint a reusable auth key in the admin console (Settings, then Keys), choose Auth key (headless) in the builder, and paste it, or add TS_AUTHKEY=tskey-auth-... to the .env above. The box then joins on its own with no approval step. Everything else is identical.

The server's own name (tailscale serve)

If the box is already on your tailnet (or you'd rather it be), skip the proxy and let the machine serve Cobblr under its own name, https://myserver.tail1234.ts.net:

  1. Put the box on the tailnet if it isn't: curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up. Its name shows in tailscale status.
  2. In the builder pick Tailscale, then Server's name, with the machine's ts.net name as the address (upgraders: set that address, set COMPOSE_PROFILES= empty, remove WEB_BIND, keep your secrets), and bring it up. No page appears yet; the app is loopback-bound until the next step.
  3. sudo tailscale serve --bg 8088 publishes it with a real certificate.

To reach either setup from outside your tailnet without forwarding a port, sudo tailscale funnel --bg 8088 (the serve variant) puts it on the internet over Tailscale's edge. Turn signup off first; Funnel must be enabled in your tailnet's ACL policy and serves only on ports 443, 8443, and 10000.

One box, many services?

The Own-hostname mode is exactly this pattern applied to Cobblr: a proxy joins the tailnet as a virtual node per service. If the box also runs other apps you'd like at their own ts.net names, the same idea generalizes with a standalone Caddy built with the tsnet plugin, one block per service. Outside this guide's scope.

DuckDNS (a free public name)

DuckDNS gives you a free name.duckdns.org and a real Let's Encrypt certificate through a DNS challenge, so the box never opens port 80 for the certificate. To actually reach the box, the name points at your public IP and you forward TCP 443 on your router to the box. That puts the instance on the internet, so set PUBLIC_SIGNUP_ENABLED=false and rely on login.

In the builder pick DuckDNS, claim the name at duckdns.org, and paste its token. This sets COBBLR_TLS_MODE=duckdns and DUCKDNS_TOKEN.

To stay off the internet instead of forwarding a port, add a local DNS entry on your router or Pi-hole mapping the name to the box's LAN IP. Do not point the public DuckDNS record itself at a private IP: DuckDNS keeps resetting it to your public address, and many routers block public names that resolve to private ones.

Cloudflare (your own domain)

If you own a domain on Cloudflare, choose Cloudflare in the builder and paste an API token scoped Zone → DNS → Edit for your zone. It works the same way as DuckDNS but with your own domain: a real certificate through a DNS challenge, with a record like cobblr.example.com pointed at your box and a port forwarded to reach it. This sets COBBLR_TLS_MODE=cloudflare and CLOUDFLARE_API_TOKEN. The local-DNS option applies here too if you'd rather not expose it.

Offline CA (no domain, no internet, no tailnet)

Choose Offline CA in the builder (COBBLR_TLS_MODE=internal). Caddy runs its own certificate authority and issues the certificate locally, so nothing leaves the box. The cost is trusting that CA once per device. After the stack is up, export the CA:

docker compose exec caddy cat /data/caddy/pki/authorities/local/root.crt > cobblr-root.crt

On iOS, install the profile and enable full trust under Settings → General → About → Certificate Trust Settings. On Android, use Settings → Security → Install a certificate → CA certificate. This is the only path that needs no network and no third party at all.

Updating

docker compose pull && docker compose up -d. Details, backups, and troubleshooting are in Operating.

Once you're in, Your first hour picks up inside the app.