Removed dockge from the app as it is not required due to the manager page picking up most of its abilities.
This commit is contained in:
10 files changed
+74
-76
No files matched your search
@@ -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://<vps>: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
|
||||
+6
-5
@@ -27,11 +27,12 @@ dist/
|
||||
|
||||
# per-deployment production env files (multi-business VPS setup — see
|
||||
# stacks/infra/compose.yaml / stacks/<business>/compose.yaml). Every real
|
||||
# stack's .env lives at stacks/<name>/.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/<name>/
|
||||
# directory) stay tracked, same as .env.local.example above.
|
||||
# stack's .env lives at stacks/<name>/.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/<name>/ directory) stay tracked,
|
||||
# same as .env.local.example above.
|
||||
stacks/*/.env
|
||||
|
||||
# Real per-business Caddy site files (deployment-specific domains, not
|
||||
|
||||
@@ -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.)
|
||||
@@ -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"
|
||||
+1
-2
@@ -58,8 +58,7 @@ effectively means root on the host. Consequences:
|
||||
both host and container (see `.env.example`) — a `docker compose -f
|
||||
<path>` 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
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<div className="min-h-screen">
|
||||
<header className="flex items-center justify-between border-b border-line bg-surface px-6 py-4">
|
||||
@@ -14,11 +12,6 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
|
||||
<Link href="/dashboard/settings" className="text-muted hover:text-ink">
|
||||
Settings
|
||||
</Link>
|
||||
{dockgeUrl && (
|
||||
<a href={dockgeUrl} target="_blank" rel="noreferrer" className="text-muted hover:text-ink">
|
||||
Dockge ↗
|
||||
</a>
|
||||
)}
|
||||
<form action={logoutAction}>
|
||||
<button type="submit" className="text-muted hover:text-ink">
|
||||
Sign out
|
||||
|
||||
@@ -7,9 +7,8 @@ const execFileAsync = promisify(execFile);
|
||||
* Every call here runs `docker compose` with `cwd` set to a stack's own
|
||||
* directory (stacks/<slug>/) rather than passing explicit -f/--env-file
|
||||
* flags — compose already auto-loads `compose.yaml` and `.env` from the
|
||||
* current directory, and this is the same convention Dockge itself uses,
|
||||
* so a stack behaves identically whether it's started by this app, by
|
||||
* Dockge, or by hand from the command line.
|
||||
* current directory, so a stack behaves identically whether it's started
|
||||
* by this app or by hand from the command line.
|
||||
*
|
||||
* This app's own container needs the Docker socket mounted and the
|
||||
* `docker compose` CLI installed (see manager/Dockerfile) — these calls
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: next-chair-blake-heritage
|
||||
|
||||
# One business's app container on the shared multi-business VPS setup —
|
||||
# see stacks/infra/compose.yaml for the shared MySQL/Caddy/Dockge this
|
||||
# attaches to, and that file's header for the exact one-time setup steps
|
||||
# see stacks/infra/compose.yaml for the shared MySQL/Caddy this attaches
|
||||
# to, and that file's header for the exact one-time setup steps
|
||||
# (create this business's database, copy .env.business.example, add a
|
||||
# Caddy site file) needed before this file can start.
|
||||
#
|
||||
|
||||
+11
-35
@@ -1,24 +1,24 @@
|
||||
name: next-chair-infra
|
||||
|
||||
# Shared infrastructure for the multi-business VPS deployment: Caddy
|
||||
# (reverse proxy + automatic TLS via Let's Encrypt), one MySQL server
|
||||
# (reverse proxy + automatic TLS via Let's Encrypt) and one MySQL server
|
||||
# shared by every business (a separate database + user per business, NOT
|
||||
# one shared schema — see step 1 below), and Dockge (a web UI for
|
||||
# starting/stopping/inspecting these compose stacks by hand).
|
||||
# one shared schema — see step 1 below).
|
||||
#
|
||||
# Lives in stacks/infra/ so Dockge (which expects one directory per
|
||||
# stack, each with its own compose.yaml) can manage this stack too —
|
||||
# see stacks/blake-heritage/, stacks/marios/ for the same shape per
|
||||
# business. Deliberately separate from docker-compose.local.yaml at the
|
||||
# Lives in stacks/infra/, one directory per stack (each with its own
|
||||
# compose.yaml) — see stacks/blake-heritage/, stacks/marios/ for the same
|
||||
# shape per business, and stacks/manager/ for the management UI's own
|
||||
# stack. Deliberately separate from docker-compose.local.yaml at the
|
||||
# repo root, which is the single-business local/Docker-Desktop setup and
|
||||
# stays untouched by any of this.
|
||||
#
|
||||
# Stack management/provisioning is handled by NextChair Manager (see
|
||||
# manager/ at the repo root) — there is no separate stack-management UI
|
||||
# alongside it.
|
||||
#
|
||||
# ── One-time setup ───────────────────────────────────────────────────────
|
||||
# docker network create next-chair-edge
|
||||
# cp .env.infra.example stacks/infra/.env (then fill in real values —
|
||||
# in particular STACKS_DIR must be this repo's absolute path on the
|
||||
# VPS, e.g. /opt/nextchair/stacks — see the STACKS_DIR comment in that
|
||||
# file for why it can't just be a relative path here)
|
||||
# cp .env.infra.example stacks/infra/.env (then fill in real values)
|
||||
# docker compose -f stacks/infra/compose.yaml --env-file stacks/infra/.env up -d
|
||||
#
|
||||
# ── Per business ──────────────────────────────────────────────────────
|
||||
@@ -98,28 +98,6 @@ services:
|
||||
networks:
|
||||
- next-chair-edge
|
||||
|
||||
dockge:
|
||||
image: louislam/dockge:1
|
||||
container_name: next-chair-dockge
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
DOCKGE_STACKS_DIR: "${STACKS_DIR}"
|
||||
ports:
|
||||
- "${DOCKGE_HOST_PORT:-5001}:5001"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- next-chair-dockge-data:/app/data
|
||||
# MUST be mounted at the identical absolute path on both host and
|
||||
# container — see the STACKS_DIR comment in .env.infra.example for
|
||||
# why (Dockge shells `docker compose` out to the HOST's dockerd via
|
||||
# the socket above, so a compose-file path only means the same
|
||||
# thing on both sides if the bind-mount doesn't change it).
|
||||
- "${STACKS_DIR}:${STACKS_DIR}"
|
||||
networks:
|
||||
- next-chair-edge
|
||||
|
||||
volumes:
|
||||
next-chair-mysql-data:
|
||||
name: next-chair-mysql-data
|
||||
@@ -127,8 +105,6 @@ volumes:
|
||||
name: next-chair-caddy-data
|
||||
next-chair-caddy-config:
|
||||
name: next-chair-caddy-config
|
||||
next-chair-dockge-data:
|
||||
name: next-chair-dockge-data
|
||||
|
||||
networks:
|
||||
next-chair-edge:
|
||||
|
||||
@@ -4,8 +4,8 @@ name: next-chair-manager
|
||||
# explains why it's a fully separate app). Its own stack, separate from
|
||||
# stacks/infra/compose.yaml, since this is real application code that
|
||||
# gets rebuilt/updated far more often than the off-the-shelf infra
|
||||
# images (MySQL, Caddy, Dockge) — a code change here shouldn't require
|
||||
# touching the infra stack at all.
|
||||
# images (MySQL, Caddy) — a code change here shouldn't require touching
|
||||
# the infra stack at all.
|
||||
#
|
||||
# cp manager/.env.example stacks/manager/.env (then fill in real values)
|
||||
# docker compose -f stacks/manager/compose.yaml --env-file stacks/manager/.env up -d --build
|
||||
|
||||
Reference in new issue
Block a user