Move static service docs into services/<name>.md companion files

Applies the new write_readme companion-doc convention to ai-stack,
paintplus, and kyber-launcher: install-time-invariant content (usage
walkthroughs, service tables, troubleshooting) moves out of the .sh
heredocs into sibling services/<name>.md files, leaving only genuinely
install-specific content inline.

- services/paintplus.md: config/cloud/GPU/ai-stack-backend/update/Caddy
  sections, picked up automatically via write_readme's companion-doc
  support.
- services/ai-stack.md: roles, GPU switcher, service URLs, cloud LLM
  provider setup, update, Caddy. ai-stack.sh can't use write_readme
  directly (its POST-INSTALL-NOTES.md filename deliberately avoids
  colliding with the vendored app's own README.md in the same
  directory), so it appends the companion file manually.
- services/kyber-launcher.md: the full SWBF2 (2017) + Kyber walkthrough,
  moved out of the root README's "Gaming scripts" section (which now
  just points here). kyber-launcher.sh now calls write_readme to deploy
  it to ~/.local/share/kyber/README.md, fixing a stale in-script pointer
  to a README section that no longer exists.
This commit is contained in:
Claude
2026-08-04 12:34:37 +00:00
parent 52b4606ab5
commit d6092dde4c
7 changed files with 277 additions and 240 deletions
+10 -111
View File
@@ -259,115 +259,14 @@ The wizard shows the detected OS in the header and warns on unknown versions.
## Gaming scripts ## Gaming scripts
Standalone scripts in `scripts/` for gaming setup — not part of the main Gaming setup walkthroughs live next to their service files, not here — see
wizard, run separately. `services/<name>.md` (e.g. [`services/kyber-launcher.md`](services/kyber-launcher.md)
for SWBF2 (2017) + Kyber: playing, hosting, and troubleshooting). It's
appended automatically to `~/.local/share/kyber/README.md` when you run
`sudo ./setup.sh kyber-launcher`.
### Star Wars Battlefront II (2017) + Kyber Also in `scripts/` (standalone, not part of the main wizard):
`setup-swbf2-linux.sh` (native Steam/Proton fixes for the base game),
**`scripts/setup-swbf2-linux.sh`** — Configure SWBF2 on native Linux Steam `setup-kyber-linux.sh` (standalone equivalent of the `kyber-launcher`
(Proton, controller, performance tweaks). service), and Wolf/Games-on-Whales container variants
(`setup-swbf2-wolf.sh`, `setup-kyber-wolf.sh`).
**`scripts/setup-kyber-linux.sh`** — Install the native Linux Kyber launcher.
Kyber is the community multiplayer replacement for SWBF2 after EA shut down
official servers in 2022. It went open-source (GPL) in January 2026.
**The correct approach is a native Linux AppImage** — not Wine or Proton for
the launcher itself. The AppImage is maintained at:
https://github.com/simonlinuxcraft/kyber-linuxport-unofficial
```bash
chmod +x scripts/setup-kyber-linux.sh
./scripts/setup-kyber-linux.sh
```
The script downloads the latest AppImage, installs a desktop entry, and
creates a `kyber` command in `~/.local/bin`.
**Every time you want to play:**
1. Open **Steam** (must be running for library validation) — do NOT click Play on SWBF2
2. Launch **Kyber** (`kyber` or from the app menu)
3. In Kyber: join a server (HOME) or create one (HOST)
4. Kyber/Maxima launches SWBF2 via its own bundled GE-Proton — wait 1-3 minutes
5. If the SWBF2 window appears but won't focus: press **Alt+Tab** or click its
taskbar entry — this is normal when the game is launched by a wrapper process
Do NOT launch SWBF2 from Steam directly. If Steam's SWBF2 is already running
when Kyber starts, kill it first — Kyber cannot inject into a Steam-launched instance.
**If Kyber says "Game Not Found":**
Click **SET GAME FOLDER** and point it to the SWBF2 install directory.
Find it with:
```bash
find ~/.steam/steam/steamapps -name "starwarsbattlefrontii.exe" 2>/dev/null | head -1 | xargs dirname
```
Paste that path into the SET GAME FOLDER dialog.
**If Origin Error: "title installed in language not entitled to play":**
Maxima's Wine prefix is missing locale registry keys — its setup commands fail silently on some systems. Fix:
```bash
cat > /tmp/swbf2_fix.reg << 'EOF'
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\Software\Origin Games\1035052]
"locale"="en_US"
"displayname"="STAR WARS Battlefront II"
[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Origin Games\1035052]
"locale"="en_US"
"displayname"="STAR WARS Battlefront II"
[HKEY_LOCAL_MACHINE\Software\Electronic Arts\EA Desktop]
"InstallSuccessful"="true"
[HKEY_LOCAL_MACHINE\Software\Origin]
"InstallSuccessful"="true"
"ClientPath"="C:\\Windows\\System32\\conhost.exe"
[HKEY_CURRENT_USER\Control Panel\International]
"Locale"="00000409"
"LocaleName"="en-US"
"sLanguage"="ENU"
EOF
WINEPREFIX=~/.local/share/maxima/wine/prefix wine64 regedit /tmp/swbf2_fix.reg
```
Then restart Kyber and try again.
**First run (one-time setup):**
1. Click **EA Account** → log in with your EA credentials in the browser
2. Click **Skip** on Nexus Mods (optional, only needed for mods)
3. EA login is cached — you stay logged in across sessions
**Hosting a private server with bots:**
- HOST → pick maps/modes → set a **name** and **PASSWORD** → Start Server
- Share the server name + password with friends; they search by name in HOME
- Bot count: in the HOST panel right side → **AUTOPLAYERS** section →
set **BOTS TEAM 1** and **BOTS TEAM 2** (e.g. 4 each) → click **UPDATE SERVER**
- Bot difficulty: the **BOT DIFFICULTY** slider (RECRUIT → OFFICER → KNIGHT → MASTER)
- After the game loads you can also update settings live and hit UPDATE SERVER again
**Requirements:**
- SWBF2 (Steam AppID 1237950) installed via Steam
(Kyber manages its own GE-Proton for launching the game)
- glibc 2.38+ — Ubuntu 24.04+, Fedora 38+, SteamOS 3.7+
- EA account (free) at ea.com
- Unprivileged user namespaces enabled (Ubuntu 24.04 restricts these by default):
```bash
sudo sysctl -w kernel.unprivileged_userns_clone=1
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
```
The setup script applies this automatically when run with sudo and saves it
to `/etc/sysctl.d/99-userns.conf` to persist across reboots.
Without this fix Kyber fails with: `bwrap: setting up uid map: Permission denied`
**If SWBF2 crashes immediately when a level starts loading:**
Likely a DXVK rendering issue, especially on integrated GPUs (Intel Iris Xe, etc.).
Disable fullscreen and HDR in the game settings file — the game writes this on first run:
```bash
PROFILE=$(find ~/.local/share/maxima -name "ProfileOptions_profile" 2>/dev/null | head -1)
sed -i 's/GstRender.FullscreenEnabled 1/GstRender.FullscreenEnabled 0/' "$PROFILE"
sed -i 's/GstRender.EnableHDR 1/GstRender.EnableHDR 0/' "$PROFILE"
```
Then restart Kyber and try hosting/joining again.
**What does NOT work:**
- Running the Windows `kyber_launcher.exe` under Wine/Proton: EA's auth
callback uses the `eadesktop://` URI scheme which has no Linux handler,
and Wine's cmd.exe crashes on long OAuth URLs anyway
- Running Kyber inside Wolf/Games-on-Whales: the Docker double-sandbox
blocks the user namespace clone that Proton requires
+71
View File
@@ -0,0 +1,71 @@
## Roles
- **Open WebUI** (chat, research, light coding) — local Ollama + any cloud providers
in one model dropdown; wired to your code via the RAG + MCP servers and Gitea.
- **PaintPlus** (separate `paintplus` service) — the front end for all image work
(inpaint / upscale / generate). Point its `AI_PROVIDER` at a cloud API, or at this
stack's local `comfyui` / `invokeai` for local image-gen.
- **Gitea + GitHub sync** — `bash gitea-github-sync.sh` mirrors repos both ways
(pull GitHub → local git, or push local → GitHub).
- **RAG / MCP / Kiwix** — retrieve just the relevant context so you feed the model
less text (saves tokens), for both local and cloud models.
- Web search uses **DuckDuckGo** (no SearXNG in this build).
## GPU switcher (small local GPU only)
One small GPU can't run local chat and local image-gen at once. Swap it:
```bash
~/docker/ai-stack/gpu-mode.sh images # before generating locally in PaintPlus
~/docker/ai-stack/gpu-mode.sh llm # back to local chat in Open WebUI
~/docker/ai-stack/gpu-mode.sh status # see which is active
```
Cloud models work anytime and need no swap.
## Service URLs
| Service | URL | Auth |
|------------|---------------------------|---------------------|
| Open WebUI | http://localhost:3000 | built-in (first visit = admin) |
| InvokeAI | http://localhost:9090 | none |
| ComfyUI | http://localhost:8188 | none |
| Kiwix | http://localhost:8181 | none |
| Gitea | http://localhost:3001 | built-in |
| Portainer | https://localhost:9443 | built-in |
## Manage the stack
```bash
cd ~/docker/ai-stack
bash start.sh # pull latest images + docker compose up -d
bash stop.sh # docker compose down
bash status.sh # GPU / container / RAG health
bash pull-models.sh # pull Ollama models (run once after first install)
```
Also a systemd unit: `sudo systemctl {start,stop,status} local-ai`
## Cloud LLM providers (Open WebUI)
Open WebUI uses an OpenAI-compatible connection list. The local RAG server is the
first entry; any cloud providers added at install follow it. Two semicolon-separated
lists in `.env`, matched by position (RAG must stay first):
```bash
# ~/docker/ai-stack/.env
OPENAI_API_BASE_URLS=http://rag-server:8001/v1;https://api.groq.com/openai/v1
OPENAI_API_KEYS=local-rag;gsk_xxx
cd ~/docker/ai-stack && docker compose up -d open-webui # apply
```
| Provider | Base URL | Key |
|----------|----------|-----|
| Groq | `https://api.groq.com/openai/v1` | https://console.groq.com/keys |
| DeepInfra | `https://api.deepinfra.com/v1/openai` | https://deepinfra.com/dash/api_keys |
| OpenAI | `https://api.openai.com/v1` | https://platform.openai.com/api-keys |
| OpenRouter | `https://openrouter.ai/api/v1` | https://openrouter.ai/keys |
Alternatively, add them at runtime in Open WebUI → Settings → Admin → Connections
(no file edits, survives image upgrades).
## Update
Re-run the `ai-stack` installer (refreshes vendored source, keeps your `.env`),
then `bash ~/docker/ai-stack/start.sh`. Or in place:
`cd ~/docker/ai-stack && bash local-ai-setup.sh --force`.
## Caddy
Open WebUI is reverse-proxied as `open-webui:8080` on `caddy_net` (or your
configured Caddy network name; attached with `docker network connect` after
start). Other services are LAN-only by default — add Caddy site blocks for
them if you want remote access.
+9 -70
View File
@@ -232,82 +232,21 @@ GPUEOF
configure_caddy_for_service "Open WebUI" "open-webui:8080" "ai" configure_caddy_for_service "Open WebUI" "open-webui:8080" "ai"
# ── Deploy notes (the app's own docs stay at $AS_DIR/README.md) ─────────── # ── Deploy notes (the app's own docs stay at $AS_DIR/README.md) ───────────
# Filename is deliberately not README.md — that name is already taken by
# the vendored app's own docs, copied into this same directory above.
# Static content (roles, GPU switcher, service URLs, etc.) lives in the
# companion services/ai-stack.md and gets appended below, same idea as
# write_readme's own companion-doc convention (lib/common.sh) but manual
# here since write_readme always targets README.md.
cat > "$AS_DIR/POST-INSTALL-NOTES.md" << MD cat > "$AS_DIR/POST-INSTALL-NOTES.md" << MD
# Local AI Stack — deployment notes (ubuntu-post-install) # Local AI Stack — deployment notes (ubuntu-post-install)
Vendored app source copied here from the \`ai-stack\` service. Full app docs: Vendored app source copied here from the \`ai-stack\` service. Full app docs:
\`README.md\` in this directory. Source: github.com/outis1one/local-ai \`README.md\` in this directory. Source: github.com/outis1one/local-ai
## Roles
- **Open WebUI** (chat, research, light coding) — local Ollama + any cloud providers
in one model dropdown; wired to your code via the RAG + MCP servers and Gitea.
- **PaintPlus** (separate \`paintplus\` service) — the front end for all image work
(inpaint / upscale / generate). Point its \`AI_PROVIDER\` at a cloud API, or at this
stack's local \`comfyui\` / \`invokeai\` for local image-gen.
- **Gitea + GitHub sync** — \`bash gitea-github-sync.sh\` mirrors repos both ways
(pull GitHub → local git, or push local → GitHub).
- **RAG / MCP / Kiwix** — retrieve just the relevant context so you feed the model
less text (saves tokens), for both local and cloud models.
- Web search uses **DuckDuckGo** (no SearXNG in this build).
## GPU switcher (small local GPU only)
One small GPU can't run local chat and local image-gen at once. Swap it:
\`\`\`bash
$AS_DIR/gpu-mode.sh images # before generating locally in PaintPlus
$AS_DIR/gpu-mode.sh llm # back to local chat in Open WebUI
$AS_DIR/gpu-mode.sh status # see which is active
\`\`\`
Cloud models work anytime and need no swap.
## Service URLs
| Service | URL | Auth |
|------------|---------------------------|---------------------|
| Open WebUI | http://localhost:3000 | built-in (first visit = admin) |
| InvokeAI | http://localhost:9090 | none |
| ComfyUI | http://localhost:8188 | none |
| Kiwix | http://localhost:8181 | none |
| Gitea | http://localhost:3001 | built-in |
| Portainer | https://localhost:9443 | built-in |
## Manage the stack
\`\`\`bash
cd $AS_DIR
bash start.sh # pull latest images + docker compose up -d
bash stop.sh # docker compose down
bash status.sh # GPU / container / RAG health
bash pull-models.sh # pull Ollama models (run once after first install)
\`\`\`
Also a systemd unit: \`sudo systemctl {start,stop,status} local-ai\`
## Cloud LLM providers (Open WebUI)
Open WebUI uses an OpenAI-compatible connection list. The local RAG server is the
first entry; any cloud providers added at install follow it. Two semicolon-separated
lists in \`.env\`, matched by position (RAG must stay first):
\`\`\`bash
# $AS_DIR/.env
OPENAI_API_BASE_URLS=http://rag-server:8001/v1;https://api.groq.com/openai/v1
OPENAI_API_KEYS=local-rag;gsk_xxx
cd $AS_DIR && docker compose up -d open-webui # apply
\`\`\`
| Provider | Base URL | Key |
|----------|----------|-----|
| Groq | \`https://api.groq.com/openai/v1\` | https://console.groq.com/keys |
| DeepInfra | \`https://api.deepinfra.com/v1/openai\` | https://deepinfra.com/dash/api_keys |
| OpenAI | \`https://api.openai.com/v1\` | https://platform.openai.com/api-keys |
| OpenRouter | \`https://openrouter.ai/api/v1\` | https://openrouter.ai/keys |
Alternatively, add them at runtime in Open WebUI → Settings → Admin → Connections
(no file edits, survives image upgrades).
## Update
Re-run the \`ai-stack\` installer (refreshes vendored source, keeps your \`.env\`),
then \`bash $AS_DIR/start.sh\`. Or in place: \`cd $AS_DIR && bash local-ai-setup.sh --force\`.
## Caddy
Open WebUI is reverse-proxied as \`open-webui:8080\` on \`${SITE_CADDY_NET:-caddy_net}\`
(attached with \`docker network connect\` after start). Other services are LAN-only by
default — add Caddy site blocks for them if you want remote access.
MD MD
if [ -f "$SELF_DIR/ai-stack.md" ]; then
cat "$SELF_DIR/ai-stack.md" >> "$AS_DIR/POST-INSTALL-NOTES.md"
fi
ensure_docker_dir_ownership "$AS_DIR" ensure_docker_dir_ownership "$AS_DIR"
echo "" echo ""
+108
View File
@@ -0,0 +1,108 @@
## Star Wars Battlefront II (2017) + Kyber
Kyber is the community multiplayer replacement for SWBF2 after EA shut down
official servers in 2022. It went open-source (GPL) in January 2026.
**The correct approach is a native Linux AppImage** — not Wine or Proton for
the launcher itself. The AppImage is maintained at:
https://github.com/simonlinuxcraft/kyber-linuxport-unofficial
This service (`sudo ./setup.sh kyber-launcher`) downloads the latest
AppImage, installs a desktop entry, and creates a `kyber` command in
`~/.local/bin`. A standalone equivalent also exists at
`scripts/setup-kyber-linux.sh` for machines not running the full wizard.
**Every time you want to play:**
1. Open **Steam** (must be running for library validation) — do NOT click Play on SWBF2
2. Launch **Kyber** (`kyber` or from the app menu)
3. In Kyber: join a server (HOME) or create one (HOST)
4. Kyber/Maxima launches SWBF2 via its own bundled GE-Proton — wait 1-3 minutes
5. If the SWBF2 window appears but won't focus: press **Alt+Tab** or click its
taskbar entry — this is normal when the game is launched by a wrapper process
Do NOT launch SWBF2 from Steam directly. If Steam's SWBF2 is already running
when Kyber starts, kill it first — Kyber cannot inject into a Steam-launched instance.
**If Kyber says "Game Not Found":**
Click **SET GAME FOLDER** and point it to the SWBF2 install directory.
Find it with:
```bash
find ~/.steam/steam/steamapps -name "starwarsbattlefrontii.exe" 2>/dev/null | head -1 | xargs dirname
```
Paste that path into the SET GAME FOLDER dialog.
**If Origin Error: "title installed in language not entitled to play":**
Maxima's Wine prefix is missing locale registry keys — its setup commands fail silently on some systems. Fix:
```bash
cat > /tmp/swbf2_fix.reg << 'EOF'
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\Software\Origin Games\1035052]
"locale"="en_US"
"displayname"="STAR WARS Battlefront II"
[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Origin Games\1035052]
"locale"="en_US"
"displayname"="STAR WARS Battlefront II"
[HKEY_LOCAL_MACHINE\Software\Electronic Arts\EA Desktop]
"InstallSuccessful"="true"
[HKEY_LOCAL_MACHINE\Software\Origin]
"InstallSuccessful"="true"
"ClientPath"="C:\\Windows\\System32\\conhost.exe"
[HKEY_CURRENT_USER\Control Panel\International]
"Locale"="00000409"
"LocaleName"="en-US"
"sLanguage"="ENU"
EOF
WINEPREFIX=~/.local/share/maxima/wine/prefix wine64 regedit /tmp/swbf2_fix.reg
```
Then restart Kyber and try again.
**First run (one-time setup):**
1. Click **EA Account** → log in with your EA credentials in the browser
2. Click **Skip** on Nexus Mods (optional, only needed for mods)
3. EA login is cached — you stay logged in across sessions
**Hosting a private server with bots:**
- HOST → pick maps/modes → set a **name** and **PASSWORD** → Start Server
- Share the server name + password with friends; they search by name in HOME
- Bot count: in the HOST panel right side → **AUTOPLAYERS** section →
set **BOTS TEAM 1** and **BOTS TEAM 2** (e.g. 4 each) → click **UPDATE SERVER**
- Bot difficulty: the **BOT DIFFICULTY** slider (RECRUIT → OFFICER → KNIGHT → MASTER)
- After the game loads you can also update settings live and hit UPDATE SERVER again
- For a headless, always-on dedicated server instead (no local Kyber client
needed to host), see the separate `kyber-server` service.
**Requirements:**
- SWBF2 (Steam AppID 1237950) installed via Steam
(Kyber manages its own GE-Proton for launching the game)
- glibc 2.38+ — Ubuntu 24.04+, Fedora 38+, SteamOS 3.7+
- EA account (free) at ea.com
- Unprivileged user namespaces enabled (Ubuntu 24.04 restricts these by default):
```bash
sudo sysctl -w kernel.unprivileged_userns_clone=1
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
```
The setup script applies this automatically when run with sudo and saves it
to `/etc/sysctl.d/99-userns.conf` to persist across reboots.
Without this fix Kyber fails with: `bwrap: setting up uid map: Permission denied`
**If SWBF2 crashes immediately when a level starts loading:**
Likely a DXVK rendering issue, especially on integrated GPUs (Intel Iris Xe, etc.).
Disable fullscreen and HDR in the game settings file — the game writes this on first run:
```bash
PROFILE=$(find ~/.local/share/maxima -name "ProfileOptions_profile" 2>/dev/null | head -1)
sed -i 's/GstRender.FullscreenEnabled 1/GstRender.FullscreenEnabled 0/' "$PROFILE"
sed -i 's/GstRender.EnableHDR 1/GstRender.EnableHDR 0/' "$PROFILE"
```
Then restart Kyber and try hosting/joining again.
**What does NOT work:**
- Running the Windows `kyber_launcher.exe` under Wine/Proton: EA's auth
callback uses the `eadesktop://` URI scheme which has no Linux handler,
and Wine's cmd.exe crashes on long OAuth URLs anyway
- Running Kyber inside Wolf/Games-on-Whales: the Docker double-sandbox
blocks the user namespace clone that Proton requires
**Fixing the base game on native Linux Steam** (EA Desktop/Origin
registration, unrelated to Kyber itself) is a separate script:
`scripts/setup-swbf2-linux.sh` — see that file's header for what it does
and its prerequisites.
+17 -1
View File
@@ -223,7 +223,17 @@ EOF
echo " Paste that path into Kyber's SET GAME FOLDER dialog." echo " Paste that path into Kyber's SET GAME FOLDER dialog."
echo "" echo ""
echo " Troubleshooting — 'Origin Error: language not entitled':" echo " Troubleshooting — 'Origin Error: language not entitled':"
echo " See README.md Gaming section for the registry fix." echo " See $INSTALL_DIR/README.md for the registry fix."
write_readme "$INSTALL_DIR" << MD
# Kyber Launcher
Native Linux AppImage client for SWBF2 (2017) community multiplayer.
- Launch: \`kyber\` (terminal) or search "Kyber Launcher" in the app menu
- AppImage: $APPIMAGE_PATH
- Update: re-run \`sudo ./setup.sh kyber-launcher\`
MD
} }
# ── Standalone bootstrap ────────────────────────────────────────────────────── # ── Standalone bootstrap ──────────────────────────────────────────────────────
@@ -248,6 +258,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
eval "$_var='${_r:-$_def}'" eval "$_var='${_r:-$_def}'"
} }
write_readme() {
local _dir="$1"; shift
mkdir -p "$_dir"
cat > "$_dir/README.md"
}
ACTUAL_USER="${SUDO_USER:-$USER}" ACTUAL_USER="${SUDO_USER:-$USER}"
ACTUAL_HOME=$(eval echo "~$ACTUAL_USER") ACTUAL_HOME=$(eval echo "~$ACTUAL_USER")
DRY_RUN="${DRY_RUN:-false}" DRY_RUN="${DRY_RUN:-false}"
+53
View File
@@ -0,0 +1,53 @@
## Configure providers / keys
Edit `src/.env` then restart (the compose file interpolates these — no env_file):
```bash
cd ~/docker/paintplus/src
nano .env # AI_PROVIDER, OPENAI_API_KEY / REPLICATE_API_KEY, HF_TOKEN
docker compose up -d --build
```
Keys: OpenAI https://platform.openai.com/api-keys · Replicate https://replicate.com/account/api-tokens
## Cloud mode (no GPU)
```bash
cd ~/docker/paintplus/src
docker compose up -d --build # starts on http://localhost:3080
docker compose logs -f
docker compose down
```
## Local GPU mode (NVIDIA, ~13 GB of models)
```bash
cd ~/docker/paintplus/src
./install-local-gpu.sh # toolkit + DNS fix + model prefetch
./bring-up-local-gpu.sh # docker compose -f docker-compose.gpu.yml up -d --build
```
GPU auto-selects models by VRAM (FLUX >=24 GB, SDXL 12-24 GB, SD 1.5 <2 GB).
## ai-stack backend (no extra GPU download)
If the `ai-stack` service is installed on this box, PaintPlus can use its
InvokeAI/ComfyUI containers instead of the cloud or its own GPU installer —
select it during install, or switch later:
```bash
cd ~/docker/paintplus/src
nano .env # AI_PROVIDER=invokeai (or comfyui), INVOKEAI_URL=http://invokeai:9090
docker network connect ai-stack_default paintplus # one-time, if not already joined
docker compose up -d --build
```
PaintPlus reaches those containers by Docker network name, not localhost —
both must be on the same network (`ai-stack_default`, ai-stack's default).
If a small GPU is shared with ai-stack's local chat, swap to images first:
`~/docker/ai-stack/gpu-mode.sh images`.
## Update the app
Re-run the PaintPlus installer (copies the latest vendored source over `src/`,
keeping your `src/.env`), then rebuild:
```bash
cd ~/docker/paintplus/src && docker compose up -d --build
```
## Caddy
Reverse-proxied as `paintplus:8000` on `caddy_net` (or your configured Caddy
network name). Cloud mode joins that network via
`src/docker-compose.override.yml`; GPU mode is attached with `docker network
connect` after start. Same for the ai-stack backend — attached to
`ai-stack_default` with `docker network connect` after start.
+9 -58
View File
@@ -209,71 +209,22 @@ OVR
configure_caddy_for_service "PaintPlus" "paintplus:8000" "paintplus" "$EXTRA_BLOCK" configure_caddy_for_service "PaintPlus" "paintplus:8000" "paintplus" "$EXTRA_BLOCK"
# ── README (deploy notes; the app's own docs are at src/README.md) ──────── # ── README (deploy notes; the app's own docs are at src/README.md) ────────
write_readme "$PP_DIR" << MD # Static usage sections (config, cloud/GPU/ai-stack modes, update, Caddy)
# live in the companion services/paintplus.md and get appended
# automatically by write_readme (lib/common.sh) — kept out of this
# heredoc since none of it depends on anything chosen during install.
write_readme "$PP_DIR" << 'MD'
# PaintPlus (deployment) # PaintPlus (deployment)
Self-hosted AI photo editor: paint a mask over any object, describe what you Self-hosted AI photo editor: paint a mask over any object, describe what you
want, and the AI replaces just that region. The application source is vendored want, and the AI replaces just that region. The application source is vendored
in ubuntu-post-install and copied here to \`src/\` (no network clone). in ubuntu-post-install and copied here to `src/` (no network clone).
App docs: \`src/README.md\`. Based on EditmaskwithAI. App docs: `src/README.md`. Based on EditmaskwithAI.
- URL: http://localhost:3080 - URL: http://localhost:3080
- No built-in login — protect via Authelia SSO if exposed. - No built-in login — protect via Authelia SSO if exposed.
- Provider: set \`AI_PROVIDER\` in \`src/.env\` (openai, replicate, local_gpu, stability, comfyui, invokeai). - Provider: set `AI_PROVIDER` in `src/.env` (openai, replicate, local_gpu, stability, comfyui, invokeai).
- \`comfyui\`/\`invokeai\` can point at this box's own \`ai-stack\` service — see below. - `comfyui`/`invokeai` can point at this box's own `ai-stack` service — see below.
## Configure providers / keys
Edit \`src/.env\` then restart (the compose file interpolates these — no env_file):
\`\`\`bash
cd $APP_DIR
nano .env # AI_PROVIDER, OPENAI_API_KEY / REPLICATE_API_KEY, HF_TOKEN
docker compose up -d --build
\`\`\`
Keys: OpenAI https://platform.openai.com/api-keys · Replicate https://replicate.com/account/api-tokens
## Cloud mode (no GPU)
\`\`\`bash
cd $APP_DIR
docker compose up -d --build # starts on http://localhost:3080
docker compose logs -f
docker compose down
\`\`\`
## Local GPU mode (NVIDIA, ~13 GB of models)
\`\`\`bash
cd $APP_DIR
./install-local-gpu.sh # toolkit + DNS fix + model prefetch
./bring-up-local-gpu.sh # docker compose -f docker-compose.gpu.yml up -d --build
\`\`\`
GPU auto-selects models by VRAM (FLUX >=24 GB, SDXL 12-24 GB, SD 1.5 <2 GB).
## ai-stack backend (no extra GPU download)
If the \`ai-stack\` service is installed on this box, PaintPlus can use its
InvokeAI/ComfyUI containers instead of the cloud or its own GPU installer —
select it during install, or switch later:
\`\`\`bash
cd $APP_DIR
nano .env # AI_PROVIDER=invokeai (or comfyui), INVOKEAI_URL=http://invokeai:9090
docker network connect ai-stack_default paintplus # one-time, if not already joined
docker compose up -d --build
\`\`\`
PaintPlus reaches those containers by Docker network name, not localhost —
both must be on the same network (\`ai-stack_default\`, ai-stack's default).
If a small GPU is shared with ai-stack's local chat, swap to images first:
\`~/docker/ai-stack/gpu-mode.sh images\`.
## Update the app
Re-run the PaintPlus installer (copies the latest vendored source over \`src/\`,
keeping your \`src/.env\`), then rebuild:
\`\`\`bash
cd $APP_DIR && docker compose up -d --build
\`\`\`
## Caddy
Reverse-proxied as \`paintplus:8000\` on \`${SITE_CADDY_NET:-caddy_net}\`. Cloud mode
joins that network via \`src/docker-compose.override.yml\`; GPU mode is attached
with \`docker network connect\` after start. Same for the ai-stack backend —
attached to \`ai-stack_default\` with \`docker network connect\` after start.
MD MD
echo "" echo ""