Serve plain HTTP only and drop the local certificate tooling
The app never terminates TLS: a reverse proxy or tunnel does, and isSecureRequest still reads X-Forwarded-Proto so cookies stay Secure. Removes the cert generator, TLS resolution and HTTP redirect, the local CA download, and the TLS envs, and trims the installer, Dockerfile health check and docs to match. Also softens the composer's loading row.
This commit is contained in:
@@ -26,20 +26,12 @@ missing):
|
||||
curl -fsSL https://url.moduletrace.com/cobble | sudo bash
|
||||
```
|
||||
|
||||
HTTPS is on by default, and a fresh install asks before continuing: it
|
||||
encrypts the connection, and phones need it to install the app and receive
|
||||
notifications. The installer creates a local CA for the machine, so each
|
||||
device trusts it once. Answer no, or pass `--no-https`, if a proxy or tunnel
|
||||
already handles HTTPS; `--yes` accepts the default without asking. Updates
|
||||
keep the mode already chosen.
|
||||
|
||||
Open the address it prints, usually `https://<your-ip>:7227`. The
|
||||
certificate is signed by a local CA the installer made, so the browser warns
|
||||
until you trust it: open `https://<your-ip>:7227/ca.crt` on the device and
|
||||
install it (see [HTTPS](#https)), then reload and create the super admin
|
||||
account. The first signup also creates the coordinator and the main
|
||||
computer, which pulls the sandbox image in the background. Give it a few
|
||||
minutes.
|
||||
The app serves plain HTTP on the port it prints, usually
|
||||
`http://<your-ip>:7227`. Put a reverse proxy or tunnel in front of it for
|
||||
HTTPS (see [HTTPS](#https)), then open the proxy's address and create the
|
||||
super admin account. The first signup also creates the coordinator and the
|
||||
main computer, which pulls the sandbox image in the background. Give it a
|
||||
few minutes.
|
||||
|
||||
Then open **Settings > Models**, add an OpenRouter key (or another provider)
|
||||
and wait for the model list to sync. This is what the bots think with.
|
||||
@@ -53,49 +45,29 @@ and wait for the model list to sync. This is what the bots think with.
|
||||
- Docker Desktop on macOS works for development and small installs, but
|
||||
Linux is the supported host.
|
||||
- Port 7227, or another port with `--port`.
|
||||
- HTTPS is on by default, with a certificate for this machine. Exposing the
|
||||
app publicly? Use `--https-cert` and `--https-key` with a real
|
||||
certificate, or `--no-https` behind a proxy or tunnel.
|
||||
- A reverse proxy or tunnel in front for HTTPS. The app itself serves plain
|
||||
HTTP and never handles certificates.
|
||||
|
||||
The installer binds to `0.0.0.0` so the app is reachable from your phone on
|
||||
the same network. Use `--bind 127.0.0.1` when a reverse proxy is the only
|
||||
thing that should reach it (with `--no-https`).
|
||||
thing that should reach it.
|
||||
|
||||
## HTTPS
|
||||
|
||||
The installer serves HTTPS by default, and a fresh install asks before
|
||||
continuing (`--yes` skips the question, `--no-https` answers it, an update
|
||||
keeps the saved mode). It generates a local CA and a certificate for this
|
||||
machine into `$COBBLE_HOME/certs` and mounts them into the container read
|
||||
only. The CA is kept across updates; the certificate is re-issued when the
|
||||
machine's addresses change or it is within 30 days of expiring, and a rerun
|
||||
of the updater does both.
|
||||
Cobble serves plain HTTP. Terminate TLS in front of it with a reverse proxy
|
||||
(Caddy, nginx, Traefik) or a tunnel (Cloudflare Tunnel, Tailscale Serve), and
|
||||
point that at `http://<this machine>:7227`:
|
||||
|
||||
Trust the CA once on each device. Until it is trusted the browser warns, and
|
||||
the installed app, its service worker and Web Push stay off:
|
||||
- Let the proxy set `X-Forwarded-Proto: https`. Cobble reads it to mark the
|
||||
sign-in cookies `Secure`; Caddy does this by default, and nginx needs
|
||||
`proxy_set_header X-Forwarded-Proto $scheme;`.
|
||||
- Pass `/ws` through as well as ordinary requests, including the upgrade.
|
||||
- Give the proxy a real certificate. Browsers treat plain HTTP as unsafe, so
|
||||
the installable app, offline support, Web Push notifications and voice
|
||||
recording stay off until the address is HTTPS.
|
||||
|
||||
- **Download:** open `https://<this machine>:7227/ca.crt` on the device, or
|
||||
copy `$COBBLE_HOME/certs/ca.crt`.
|
||||
- **iPhone or iPad:** open `https://<this machine>:7227/ca.mobileconfig`
|
||||
instead. iOS offers the profile in one tap; install it, then turn it on
|
||||
under Settings > General > About > Certificate Trust Settings.
|
||||
- **Android:** Settings > Security > Encryption & credentials > Install a
|
||||
certificate > CA certificate.
|
||||
- **macOS:** add it to the login keychain and set it to Always Trust.
|
||||
- **Linux:** copy it into `/usr/local/share/ca-certificates/` and run
|
||||
`sudo update-ca-certificates`.
|
||||
|
||||
Options for the certificate:
|
||||
|
||||
- A VPN name or address the installer did not detect: `--https-host NAME`,
|
||||
repeatable.
|
||||
- Your own certificate (a public CA, an internal CA, `tailscale cert`):
|
||||
`--https-cert FILE --https-key FILE`. Rerun the installer when it is
|
||||
renewed.
|
||||
- Replace the local CA, for example after trusting the wrong one:
|
||||
`--https-regen`. Every device must trust the new CA.
|
||||
- Plain HTTP with a proxy or tunnel in front: `--no-https`.
|
||||
- Turn HTTPS back on after `--no-https`: `--https`.
|
||||
Nothing on the machine needs a certificate installed: the browser only ever
|
||||
talks to the proxy. See the Help page in the app for the common proxy fixes.
|
||||
|
||||
## Update and uninstall
|
||||
|
||||
@@ -126,17 +98,11 @@ curl -fsSL https://url.moduletrace.com/cobble | sudo bash -s -- --uninstall --pu
|
||||
| `--image IMAGE` | Container image, default `ghcr.io/moduletrace/cobble` |
|
||||
| `--version TAG` | Image tag, default `latest` |
|
||||
| `--extra-network NET` | Join another Docker network, for a tunnel or reverse proxy |
|
||||
| `--no-https` | Serve plain HTTP, for a proxy or tunnel in front |
|
||||
| `--https` | Serve HTTPS again after `--no-https` |
|
||||
| `--https-host VALUE` | Names or IPs the certificate covers, repeatable |
|
||||
| `--https-cert FILE` | Use your own certificate instead of the local CA |
|
||||
| `--https-key FILE` | Its private key, given with `--https-cert` |
|
||||
| `--https-regen` | Replace the local CA and the certificate |
|
||||
| `--force` | Recreate the container even when it is current |
|
||||
| `--no-pull` | Use an image that is already on the machine |
|
||||
| `--skip-backup` | Update without a database backup |
|
||||
| `--no-docker-install` | Fail instead of installing Docker |
|
||||
| `--yes`, `-y` | Accept the defaults without asking (HTTPS on) |
|
||||
| `--yes`, `-y` | Accept the defaults without asking |
|
||||
| `--uninstall` | Stop and remove the app container |
|
||||
| `--purge` | With `--uninstall`, also delete the data directory |
|
||||
|
||||
@@ -149,7 +115,6 @@ Everything that must survive an update lives under the install directory:
|
||||
.env # generated once, mode 600
|
||||
install.conf # installer state
|
||||
backups/ # pre-update database snapshots
|
||||
certs/ # the local CA and the certificate (HTTPS)
|
||||
data/
|
||||
db/cobble
|
||||
db/.backups/
|
||||
@@ -157,15 +122,14 @@ Everything that must survive an update lives under the install directory:
|
||||
computers/<id>/ # each computer's home directory
|
||||
```
|
||||
|
||||
`.env` holds the port, the encryption keys and the `TLS_*` certificate
|
||||
paths. The keys encrypt sessions and settings, so keep a copy and do not
|
||||
rotate them without re-entering provider keys and other secrets. Provider
|
||||
keys, MCP servers, tools and app settings are managed in the app, not in
|
||||
`.env`.
|
||||
`.env` holds the port and the encryption keys. The keys encrypt sessions and
|
||||
settings, so keep a copy and do not rotate them without re-entering provider
|
||||
keys and other secrets. Provider keys, MCP servers, tools and app settings
|
||||
are managed in the app, not in `.env`.
|
||||
|
||||
Edit `.env` and run `docker restart cobble` to apply changes. The installer
|
||||
only appends missing values and keeps what is already there, apart from the
|
||||
port and the `TLS_*` entries it manages.
|
||||
port it manages.
|
||||
|
||||
The app container is started with the Docker socket mounted and
|
||||
`MAIN_SERVER=1`, so it can create computer containers and run cron, the
|
||||
@@ -193,45 +157,21 @@ bun run db:schema
|
||||
bun run dev
|
||||
```
|
||||
|
||||
Open `http://localhost:7227`, or `https://localhost:7227` once `certs/`
|
||||
exists. With no users, every page goes to `/auth/signup` to create the super
|
||||
admin. For a headless setup:
|
||||
Open `http://localhost:7227`. With no users, every page goes to
|
||||
`/auth/signup` to create the super admin. For a headless setup:
|
||||
|
||||
```bash
|
||||
SEED_SUPER_ADMIN_PASSWORD=... bun run seed
|
||||
```
|
||||
|
||||
The development server reads the same `TLS_*` variables as the container, so
|
||||
it can serve HTTPS too. That is how to try the app from a phone over a VPN,
|
||||
where the secure context (installed app, Web Push, voice) needs it:
|
||||
|
||||
```bash
|
||||
bun run dev:phone -- --host cobble-laptop.tailnet-name.ts.net
|
||||
```
|
||||
|
||||
That generates `certs/` and starts the dev server with it, with no `.env`
|
||||
edits. Afterwards any server, `bun run dev` or `bun run start`, reuses the
|
||||
certificate whenever `certs/server.crt` and `certs/server.key` exist; set
|
||||
`TLS_DISABLED=1` to serve plain HTTP instead. `bun run gen:certs` on its own
|
||||
regenerates them if you need to add a name.
|
||||
|
||||
Open `https://<the name you passed>:7227` on the phone and install the CA
|
||||
from `https://<the name you passed>:7227/ca.mobileconfig` first. On the
|
||||
laptop, trust the same `certs/ca.crt` once, so `https://localhost:7227`
|
||||
stops warning.
|
||||
|
||||
With a certificate the server also listens one port above (`7228`) for
|
||||
plain HTTP and redirects to the HTTPS page, so a stray
|
||||
`http://localhost:7228/...` link still lands. The HTTPS port itself cannot
|
||||
answer plain HTTP, so `http://localhost:7227` still fails; use
|
||||
`HTTP_REDIRECT_PORT` to move the redirect. The container publishes only the
|
||||
HTTPS port, so the redirect is reachable there only if that second port is
|
||||
published.
|
||||
The development server serves plain HTTP, the same as the container. To try
|
||||
the app from a phone, run a proxy or tunnel in front of it (see
|
||||
[HTTPS](#https)); the installed app, Web Push and voice need that secure
|
||||
context.
|
||||
|
||||
| Command | Purpose |
|
||||
| -------------------- | ------------------------------------ |
|
||||
| `bun run dev` | Development server |
|
||||
| `bun run dev:phone` | Dev server over HTTPS for a phone |
|
||||
| `bun run start` | Production server on the host |
|
||||
| `bun run typecheck` | Type-check |
|
||||
| `bun run test` | Run the test suite |
|
||||
@@ -239,7 +179,6 @@ published.
|
||||
| `bun run seed:bots` | Add a sample crew |
|
||||
| `bun run db:schema` | Sync the schema and types |
|
||||
| `bun run gen:favicon` | Regenerate favicons and PWA assets |
|
||||
| `bun run gen:certs` | Generate a local HTTPS certificate |
|
||||
|
||||
The app is Bun, [`@moduletrace/bunext`](https://github.com/Moduletrace/bunext),
|
||||
SQLite via [`@moduletrace/bun-sqlite`](https://github.com/Moduletrace/bun-sqlite),
|
||||
|
||||
Reference in New Issue
Block a user