diff --git a/.env.infra.example b/.env.infra.example index dc8091b..4baf22a 100644 --- a/.env.infra.example +++ b/.env.infra.example @@ -22,15 +22,3 @@ ACME_EMAIL="you@example.com" # testing on a machine already using those ports for something else. CADDY_HTTP_PORT=80 CADDY_HTTPS_PORT=443 - -# ── Dockge (stack management UI — http://:5001) ─────────────────── -# This repo's absolute path on the VPS, e.g. "/opt/nextchair/stacks" — NOT -# a relative path. Dockge (and the management UI in manager/) shell -# `docker compose` out to the HOST's dockerd via the mounted Docker -# socket, so a compose-file path only resolves to the same file on both -# sides if the bind-mount doesn't change it — meaning this must be -# mounted at the identical path inside the container too (see -# stacks/infra/compose.yaml's dockge service). Get this wrong and Dockge -# will either fail to find your stacks or manage the wrong path entirely. -STACKS_DIR="/opt/nextchair/stacks" -DOCKGE_HOST_PORT=5001 diff --git a/.gitignore b/.gitignore index 1ed4174..819d6d8 100644 --- a/.gitignore +++ b/.gitignore @@ -27,11 +27,12 @@ dist/ # per-deployment production env files (multi-business VPS setup — see # stacks/infra/compose.yaml / stacks//compose.yaml). Every real -# stack's .env lives at stacks//.env (Dockge's own directory -# convention) — this one wildcard rule covers every current and future -# stack without another .gitignore edit. .env.infra.example and -# .env.business.example (the templates you copy into each stacks// -# directory) stay tracked, same as .env.local.example above. +# stack's .env lives at stacks//.env (one directory per stack, +# same convention NextChair Manager's provisioning uses) — this one +# wildcard rule covers every current and future stack without another +# .gitignore edit. .env.infra.example and .env.business.example (the +# templates you copy into each stacks// directory) stay tracked, +# same as .env.local.example above. stacks/*/.env # Real per-business Caddy site files (deployment-specific domains, not diff --git a/README.md b/README.md index 9d81401..a67e408 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ docker run --rm node:22-alpine sh -c \ node -e \"const h=require('/tmp/gen/node_modules/bcryptjs').hashSync('your-password',12); console.log('MANAGER_PASSWORD_HASH=\\\"'+h.replace(/\\$/g,'\\$\\$')+'\\\"')\"" ``` -### 1. Shared infrastructure — network, MySQL, Caddy, Dockge +### 1. Shared infrastructure — network, MySQL and Caddy ```bash docker network create next-chair-edge @@ -60,7 +60,6 @@ Edit `stacks/infra/.env`: - `MYSQL_ROOT_PASSWORD` — the first secret you generated above. - `MYSQL_HOST_PORT` — set this to `127.0.0.1:3306` so MySQL is only exposed on the VPS loopback interface, not publicly. You can still connect to it remotely through an SSH tunnel. - `ACME_EMAIL` — a real address you check (Let's Encrypt renewal notices). -- `STACKS_DIR` — the absolute clone path, e.g. `/opt/nextchair/stacks`. ```bash docker compose -f stacks/infra/compose.yaml --env-file stacks/infra/.env up -d @@ -189,3 +188,46 @@ docker compose -f stacks/manager/compose.yaml --env-file stacks/manager/.env up ``` If both the business app and Manager changed, do both update steps. + +## Upgrading from a version that included Dockge (one-time) + +Dockge used to run alongside NextChair Manager as a separate stack +management UI. It's no longer part of the shared infrastructure stack — +Manager is the only tool needed to provision and manage business stacks, +so the two were redundant. If your server was set up before this change, +existing tenant databases, tenant containers, business Compose files, and +the global SMTP/VAPID settings are all unaffected — this only removes the +old Dockge container. + +Pull the change, then re-apply the infra stack with `--remove-orphans` so +Docker removes the container that's no longer defined in +`stacks/infra/compose.yaml`: + +```bash +cd /opt/nextchair +git pull + +docker compose \ + -f stacks/infra/compose.yaml \ + --env-file stacks/infra/.env \ + up -d --remove-orphans +``` + +`--remove-orphans` only removes containers Compose no longer recognizes +(the old `next-chair-dockge` container) — it does not touch Caddy, MySQL, +or their volumes. + +This does **not** delete Dockge's own data volume +(`next-chair-dockge-data`) — Docker never removes volumes on its own, and +this command has no reason to either. Once you've confirmed Caddy, MySQL +and every business are still healthy, you can remove that now-unused +volume by hand: + +```bash +docker volume rm next-chair-dockge-data +``` + +Finally, `STACKS_DIR` and `DOCKGE_HOST_PORT` in `stacks/infra/.env` were +only ever used by Dockge and are safe to delete from that file — nothing +else in the infra stack reads them. (Manager keeps its own separate +`STACKS_DIR` in `stacks/manager/.env`; leave that one alone.) diff --git a/manager/.env.example b/manager/.env.example index 690cb4f..fc73aa7 100644 --- a/manager/.env.example +++ b/manager/.env.example @@ -29,8 +29,12 @@ MYSQL_PORT="3306" MYSQL_ROOT_PASSWORD="replace-me" # ── Docker / stacks ────────────────────────────────────────────────────── -# Must be the identical absolute path as stacks/infra/.env's STACKS_DIR — -# see that file's comment for why. +# This repo's absolute path on the VPS, e.g. "/opt/nextchair/stacks" — NOT +# a relative path. This container shells `docker compose` out to the +# HOST's dockerd via the mounted Docker socket (see src/lib/docker.ts), so +# a compose-file path only resolves to the same file on both sides if the +# bind-mount doesn't change it — meaning this must be mounted at the +# identical path inside the container too (see stacks/manager/compose.yaml). STACKS_DIR="/opt/nextchair/stacks" # Every business's compose.yaml (see src/lib/compose-template.ts) uses # this image tag — rebuild with `docker build -t nextchair-app:latest .` @@ -38,7 +42,3 @@ STACKS_DIR="/opt/nextchair/stacks" # "Update" button (or `docker compose up -d --force-recreate`) to pick it # up. NEXTCHAIR_IMAGE="nextchair-app:latest" - -# ── Optional ───────────────────────────────────────────────────────────── -# Shown as a link in the dashboard header if set. -DOCKGE_URL="http://your-vps-ip:5001" diff --git a/manager/README.md b/manager/README.md index 8e9b118..d8a288c 100644 --- a/manager/README.md +++ b/manager/README.md @@ -58,8 +58,7 @@ effectively means root on the host. Consequences: both host and container (see `.env.example`) — a `docker compose -f ` command run from inside this container is executed by the *host's* dockerd, so the path only means the same file on both sides if - the mount doesn't change it. This is the same constraint Dockge itself - has. + the mount doesn't change it. ## Setup diff --git a/manager/src/app/dashboard/layout.tsx b/manager/src/app/dashboard/layout.tsx index d34c299..4aeb42f 100644 --- a/manager/src/app/dashboard/layout.tsx +++ b/manager/src/app/dashboard/layout.tsx @@ -2,8 +2,6 @@ import Link from "next/link"; import { logoutAction } from "./logout-action"; export default function DashboardLayout({ children }: { children: React.ReactNode }) { - const dockgeUrl = process.env.DOCKGE_URL; - return (
@@ -14,11 +12,6 @@ export default function DashboardLayout({ children }: { children: React.ReactNod Settings - {dockgeUrl && ( - - Dockge ↗ - - )}