Deployment guide
PoB-Enhanced is one container. It needs no database, keeps its few files (your current build, saved builds and
item art) in /data, and serves the web UI, the REST API and the MCP endpoint on a single port
(8080). Pick the setup that matches where you want it to run.
Choose a setup
There is no login. Anyone who can reach the port can view and change the loaded build. Keep it on your own PC, a trusted home network, or a tailnet. Never forward the port to the internet.
Docker Desktop (Windows and macOS)
- Install Docker Desktop and start it. On Windows, accept the WSL 2 option when the installer asks.
- Open a terminal (PowerShell on Windows, Terminal on macOS) and run:
The first start downloads the image (a few hundred MB).docker run -d --name pob-enhanced --restart unless-stopped -p 8080:8080 -v pob2-data:/data ghcr.io/skitty4fingers/pob-enhanced:latest-v pob2-data:/datakeeps your builds when the container is replaced by an update. - Open http://localhost:8080. Continue with First run.
Port 8080 taken? Use another host port, for example -p 8090:8080, and open
http://localhost:8090.
Docker Compose
Compose keeps the settings in a file and makes updates one command.
- Download the Compose file:
curl -O https://raw.githubusercontent.com/Skitty4fingers/PoB-Enhanced/main/compose.image.yml - Optional: create a
.envfile next to it (see Settings), for example:POB2_PORT=8080 POB2_BIND=127.0.0.1 - Start it:
docker compose -f compose.image.yml up -d
The Compose file listens on 127.0.0.1 by default, so only this machine can reach it, and keeps
your builds in the pob2-data volume. See the next section to open it up.
Open it to your network
To use it from another PC, a tablet or your phone on the same network:
- In
.env, setPOB2_BIND=0.0.0.0(Compose only;docker run -p 8080:8080already listens on every address). - Set
POB2_ALLOWED_HOSTSto the names and IPs other devices will type, for examplePOB2_ALLOWED_HOSTS=gaming-pc,192.168.1.20. The web UI works without it; the MCP endpoint (/mcp) rejects unknown host names to block DNS-rebinding attacks. - Restart:
docker compose -f compose.image.yml up -d, then browse tohttp://192.168.1.20:8080from the other device.
TrueNAS SCALE
- Open Apps → Discover Apps and click Custom App.
- Application name:
pob-enhanced. - Image: repository
ghcr.io/skitty4fingers/pob-enhanced, taglatest, pull policy Always pull (so a restart picks up new versions). - Environment variables: add
POB2_ALLOWED_HOSTSwith your NAS name and IP, for exampletruenas,192.168.1.147. - Network → Ports: container port
8080, host port8080(or any free port), protocol TCP. - Storage: add a host path (for example a dataset
apps/pob2) mounted at/data, so builds survive updates. Give it to user ID 1000, or use an ixVolume. Click Install. - When the app shows Running, open
http://<nas>:8080.
To update, stop and start the app (with Always pull it fetches the newest image).
Unraid
- Go to Docker → Add Container.
- Name:
pob-enhanced, Repository:ghcr.io/skitty4fingers/pob-enhanced:latest, Network type: Bridge. - Add another Path, Port, Variable… → Port: container
8080, host8080. - Add another Path, Port, Variable… → Variable: key
POB2_ALLOWED_HOSTS, valuetower,192.168.1.30(your server's name and IP). - Add another Path, Port, Variable… → Path: container
/data, host/mnt/user/appdata/pob-enhanced. - Click Apply, then open
http://<server>:8080. Update from the Docker tab with Check for updates.
Portainer or Synology Container Manager
Create a stack (Portainer: Stacks → Add stack; Synology: Container Manager → Project → Create) with this Compose file:
services:
pob2:
image: ghcr.io/skitty4fingers/pob-enhanced:latest
ports:
- "8080:8080"
environment:
POB2_ALLOWED_HOSTS: "nas,192.168.1.20" # the names/IPs you browse to
volumes:
- pob2-data:/data # current build and saved builds
restart: unless-stopped
volumes:
pob2-data:
Deploy it and open http://<nas>:8080. To update, pull the image again and redeploy the stack.
Tailscale (private HTTPS, no open ports)
compose.tailscale.yml puts PoB-Enhanced behind a Tailscale sidecar with a real certificate. Only
devices on your tailnet can reach it, at https://pob2.<tailnet>.ts.net.
- In the Tailscale admin console, enable
MagicDNS and HTTPS Certificates, and note your tailnet name (like
tail1234.ts.net). - Create an auth key.
- Get the code and settings:
git clone https://github.com/Skitty4fingers/PoB-Enhanced.git cd PoB-Enhanced cp .env.example .env # set TS_AUTHKEY and TS_TAILNET - Start it:
docker compose -f compose.tailscale.yml up -d --build - Open
https://pob2.<tailnet>.ts.netfrom any device on your tailnet.
Without an auth key, docker compose -f compose.tailscale.yml logs tailscale prints a
login link. Funnel (public exposure) is disabled.
Build from source
git clone https://github.com/Skitty4fingers/PoB-Enhanced.git
cd PoB-Enhanced
docker compose -f compose.enhanced.yml up -d --build
The first build takes a few minutes: it compiles LuaJIT and the web UI. To update, run git pull
and the same command again.
Without Docker (Linux, macOS, WSL)
You need Python 3.10+, uv, Node 22+, git and a C compiler.
git clone https://github.com/Skitty4fingers/PoB-Enhanced.git
cd PoB-Enhanced
scripts/setup-engine.sh # builds LuaJIT + lua-utf8, installs Python deps, builds the web UI
export PATH="$HOME/.local/bin:$PATH"
uv run --directory python pob2-web # http://127.0.0.1:8080
PoB needs LuaJIT from commit 2460b3ff (2026-07-20) or newer; distro packages are
too old. The setup script builds the right one into ~/.local.
First run
- Click Import and paste a PoB share code, a pobb.in / pastebin link, or your poe.ninja
character page:
https://poe.ninja/poe2/profile/<account>/<league>/character/<name>. - Open the Config tab and set enemy conditions, buffs and charges to how you play.
- Open the Help tab (or the ? button) for a tour of every tool.
- Later, press Update to re-import your character. Config settings are kept.
Your build is saved after every change and comes back after a restart. Use Builds to keep named copies, and Undo (Ctrl+Z) to step back through any change.
Connect an AI agent (MCP)
The MCP endpoint is http://localhost:8080/mcp (Streamable HTTP). The app's AI / MCP
tab shows these settings filled in with your server's address. Agents share the live build with the web UI, the UI
refreshes as they work, and anything they change can be undone.
On your computer
These run where you are, so they reach the server directly. From another machine, use the server's address (for
example http://192.168.1.20:8080/mcp) and add that name or IP to POB2_ALLOWED_HOSTS.
Claude Code
claude mcp add --transport http pob2 http://localhost:8080/mcpClaude Desktop
The config file starts local programs, so bridge with mcp-remote (needs Node.js). Settings →
Developer → Edit Config, then restart Claude. For a non-localhost http:// address add
"--allow-http" to the args.
{
"mcpServers": {
"pob2": { "command": "npx", "args": ["-y", "mcp-remote", "http://localhost:8080/mcp"] }
}
}ChatGPT users: Codex CLI
OpenAI's agent for the terminal and IDE, signed in with your ChatGPT account.
codex mcp add pob2 --url http://localhost:8080/mcp
or in ~/.codex/config.toml:
[mcp_servers.pob2]
url = "http://localhost:8080/mcp"Gemini users: Antigravity or Gemini CLI
Personal Google AI accounts moved from Gemini CLI to Antigravity in June 2026. Add the server
in ~/.gemini/config/mcp_config.json (or type /mcp in the CLI); remote servers use
serverUrl:
{ "mcpServers": { "pob2": { "serverUrl": "http://localhost:8080/mcp" } } }
Gemini CLI (API key or Code Assist for teams):
gemini mcp add --transport http --scope user pob2 http://localhost:8080/mcpCursor, VS Code, Cline, Zed and other MCP clients
{ "mcpServers": { "pob2": { "url": "http://localhost:8080/mcp" } } }
A stdio-only client can run its own copy instead (it does not share the web UI's build):
{ "mcpServers": { "pob2": { "command": "docker", "args": ["run", "--rm", "-i", "ghcr.io/skitty4fingers/pob-enhanced:latest", "pob2-mcp"] } } }Self-hosted models
Run a local model and let it drive PoB-Enhanced. Pick a model with tool calling (Qwen 3, Llama 3.1 or newer,
Mistral Small...). Clients running in Docker reach the server at host.docker.internal (on Linux start
them with --add-host=host.docker.internal:host-gateway); add host.docker.internal to
POB2_ALLOWED_HOSTS.
LM Studio (0.3.17 or newer)
Right sidebar → Program → Install → Edit mcp.json:
{ "mcpServers": { "pob2": { "url": "http://localhost:8080/mcp" } } }Open WebUI with Ollama (0.6.31 or newer)
- As an admin: Admin Settings → External Tools (Integrations in some versions) → +.
- Type MCP (Streamable HTTP) (not OpenAPI), authentication None, URL
http://host.docker.internal:8080/mcp. - In a chat, enable the pob2 tools from the tools menu.
LibreChat
mcpServers:
pob2:
type: streamable-http
url: http://host.docker.internal:8080/mcpCloud chat apps: ChatGPT, Grok, Gemini, Muse, Claude.ai
These connect from the provider's servers, so they need a public HTTPS address (they reject localhost and private addresses). A tunnel is the quickest way:
cloudflared tunnel --url http://localhost:8080 # Cloudflare quick tunnel, no account needed
ngrok http 8080 # or ngrok
Add the hostname it prints (for example word-word.trycloudflare.com) to
POB2_ALLOWED_HOSTS and restart, then use https://<that-host>/mcp:
| App | Setup |
|---|---|
| ChatGPT | Settings → Apps & Connectors → Advanced settings → Developer mode, then Settings → Connectors → Create: URL, authentication No authentication. Use it from a chat's + menu. Which plans allow custom connectors varies; check OpenAI's help pages. |
| Grok | grok.com/connectors → New Connector → Custom
(paid plans). Through the xAI API, pass {"type": "mcp", "server_label": "pob2", "server_url": "https://…/mcp"} as a tool. |
| Gemini app | Connected Apps → add custom, where your plan offers it (it rolled out with Gemini Spark on Google AI Ultra). Otherwise use Antigravity above. |
| Meta Muse | No MCP menu yet. Ask Muse to connect to the MCP server at your URL itself (it can save
that as a skill), or add a Custom Connector for the REST API from https://…/openapi.json. |
| Claude.ai | Settings → Connectors → Add custom connector. |
There is no login. While the tunnel runs, anyone who learns its address can view and change the loaded build (Undo brings it back; nothing else on your machine is exposed). Keep the address private and stop the tunnel when you are done.
Updating
| Setup | Update |
|---|---|
| docker run | docker pull ghcr.io/skitty4fingers/pob-enhanced:latest, then
docker rm -f pob-enhanced and run the original command again (the pob2-data volume
keeps your builds) |
| Compose | docker compose -f compose.image.yml pull && docker compose -f compose.image.yml up -d |
| TrueNAS | Stop and start the app (pull policy Always) |
| Unraid | Docker tab → Check for updates → Apply update |
| Source / no Docker | git pull, then rebuild or rerun scripts/setup-engine.sh |
Settings
| Variable | Default | What it does |
|---|---|---|
POB2_PORT | 8080 | Host port (Compose files) |
POB2_BIND | 127.0.0.1 | Address to listen on (Compose). 0.0.0.0 makes it reachable from your network |
POB2_ALLOWED_HOSTS | none | Extra host names accepted by /mcp, comma-separated. localhost always works |
POB2_IMAGE | ghcr.io/skitty4fingers/pob-enhanced:latest | Image for compose.image.yml |
POB2_DATA | /data | Folder for the current build, saved builds and item art (mount a volume here) |
TS_AUTHKEY, TS_TAILNET | none | Tailscale setup (compose.tailscale.yml) |
Troubleshooting
“port is already allocated” or the page won't load
Another program uses port 8080. Pick another host port (-p 8090:8080 or
POB2_PORT=8090) and open that port instead.
It works on the server but not from my other PC or phone
With Compose, set POB2_BIND=0.0.0.0 and restart. Check the server's firewall allows the port.
The AI agent can't connect to /mcp (error about the Host header)
Add the exact name or IP the agent uses to POB2_ALLOWED_HOSTS, for example
POB2_ALLOWED_HOSTS=nas,192.168.1.20, and restart the container.
My build disappeared after an update
The container had no volume at /data, so the new container started empty. Add one (see your
setup above), then import again or press Update. From then on builds survive updates.
'=' expected near '+' when running without Docker
Your LuaJIT is too old. Run scripts/setup-engine.sh and make sure ~/.local/bin comes
first on your PATH (or set POB2_LUAJIT).
The passive tree shows plain circles
The tree artwork is missing. It ships in tree-art/ and in the Docker image; if you moved the
folder, set POB2_TREE_ART to its path.
Numbers look wrong
Check the Config tab first: enemy conditions, buffs and charges change every number. Mods PoB can't model are flagged “unmodelled” and count as zero.
Still stuck? Open an issue
with your setup and the container log (docker logs pob-enhanced).