# Deploying the armory on Nox This fork of [r-o-b-o-t-o/azerothcore-armory](https://github.com/r-o-b-o-t-o/azerothcore-armory) (MIT) is set up to run as a Portainer stack on Nox, alongside the Mythica web page, reading the AzerothCore databases on the game server over the LAN. **It must not run on the AzerothCore VM (192.168.1.60).** That box is tuned for the playerbot load; anything extra there means redoing that balancing. Nothing in this procedure touches the game server — the armory only reads its databases. --- ## Why the model data is a manual step The armory needs about 2 GB of processed 3D model data — bone sets, mo3 meshes, textures, and the per-race character descriptors. Upstream ships a `fetchdata` tool that downloads this from Zam's CDN. **It no longer works.** Zam reorganised that part of the CDN, and every character path now 404s (`meta/character/*`, `meta/charactercustomization2/*` — checked against the `live`, `wrath` and `classic` prefixes and several filename variants). The armor and item paths still resolve, so a run appears to succeed while silently producing no character data, and the app then fails at startup on `data/meta/charactercustomization2/1_0.json`. The only remaining source is the snapshot in upstream's v1.0.0 release. That snapshot is mirrored into this fork's own release so the fork does not depend on GitHub staying up for the one piece that cannot be regenerated. The mirrored copy is **split into five parts** because Nginx Proxy Manager in front of the forge rejects request bodies at that size (500 MB uploads fine, 2 GB returns 413). Raising `client_max_body_size` on the forge's proxy host would let it be stored as a single file, if that is ever worth doing. --- ## 1. Put the model data on Nox Once. Redeploying the stack does not disturb it. ```bash sudo mkdir -p /opt/mythica-armory/data /opt/mythica-armory/logs sudo chown -R "$USER:$USER" /opt/mythica-armory # else the downloads below fail cd /opt/mythica-armory/data BASE=https://gitlab.hallsworth.ca/yrtria/azerothcore-armory/releases/download/v1.0.0 for i in 0 1 2 3 4; do curl -LO $BASE/data.tar.gz.part-$i; done curl -LO $BASE/SHA256SUMS.txt cat data.tar.gz.part-* > data.tar.gz sha256sum -c --ignore-missing SHA256SUMS.txt # data.tar.gz must say OK tar xzf data.tar.gz rm -f data.tar.gz data.tar.gz.part-* ``` Afterwards `/opt/mythica-armory/data` holds four directories — `meta`, `bone`, `mo3`, `textures` — totalling roughly 2.5 GB unpacked. Ownership by your own user is fine — the container reads these as root either way, and it keeps the download and extract steps out of `sudo`. The DBC `.csv` files are **not** part of this. They are committed to the repo and travel in the image, so they stay in step with the code. > `data.tar.gz.UPSTREAM-GITHUB-LINK.txt` on the same release is not the archive. > It is the original external reference Forgejo recorded during migration — a > short-lived signed GitHub URL, kept only for provenance. ## 2. Create the Portainer stack Repository stack, same pattern as `wow-web-page`: | Field | Value | |---|---| | Repository URL | `https://gitlab.hallsworth.ca/yrtria/azerothcore-armory.git` | | Reference | `refs/heads/master` | | Compose path | `docker-compose.mythica.yml` | Environment variables — `ARMORY_DB_USER` and `ARMORY_DB_PASS` are required and the stack refuses to start without them: | Variable | Value | |---|---| | `ARMORY_DB_USER` | database user (see §4) | | `ARMORY_DB_PASS` | its password | | `ARMORY_DB_HOST` | `192.168.1.60` | | `ARMORY_WEBSITE_URL` | `https://armory.dionysismedia.ca` once proxied, otherwise `http://192.168.1.77:48733` | | `ARMORY_WEBSITE_NAME` | `Mythica` | | `ARMORY_REALM_ID` | `1` | | `ARMORY_DATA_DIR` | `/opt/mythica-armory/data` | | `ARMORY_LOG_DIR` | `/opt/mythica-armory/logs` | The first build compiles TypeScript, so it takes a few minutes. It listens on 48733. ## 3. Reverse proxy Add a proxy host in NPM pointing at `192.168.1.77:48733`. To embed it in the main site instead of giving it its own subdomain, set `ARMORY_IFRAME_ENABLED=1` and `ARMORY_IFRAME_URL` to the page that hosts the iframe, then use the snippet in the upstream README. That path keeps the site's own header and navigation around it. ## 4. Database access `acore` is already granted from `192.168.1.%` and MySQL on the game server binds `0.0.0.0`, so this works with no changes. But the armory only ever reads, and it is public-facing, so a dedicated read-only user is worth the two minutes: ```sql CREATE USER 'armory'@'192.168.1.%' IDENTIFIED BY ''; GRANT SELECT ON acore_characters.* TO 'armory'@'192.168.1.%'; GRANT SELECT ON acore_world.* TO 'armory'@'192.168.1.%'; GRANT SELECT ON acore_auth.* TO 'armory'@'192.168.1.%'; FLUSH PRIVILEGES; ``` ## 5. Things to know - **Item icons and tooltips come from a third-party AoWoW instance** (`wowgaming.altervista.org` by default) — they are hotlinked, so they break if that site moves or goes down. Point `ARMORY_AOWOW_URL` at your own AoWoW to remove that dependency. This is the one remaining external asset dependency; the model data is now self-hosted. - **The armory has its own talent view** with dual-spec support, which overlaps the talent page already in `WoW-Web-Page`. Decide which one owns the character page rather than shipping both. - **The Dockerfile builds from `node:16`**, which is end-of-life. It builds and runs fine; bumping it is a separate change from getting this deployed. - **`hideGameMasters` is off** in this stack, unlike upstream. GM accounts on this realm belong to real players — `Spinnaker` among them — so hiding them would hide people who should be listed. Set `ARMORY_HIDE_GMS=1` to restore upstream behaviour. - **Service accounts are hidden** via `hideBotAccounts` / `botAccountPatterns`, a comma-separated list of LIKE patterns defaulting to `RNDBOT%,ahouse` — the Playerbots accounts and the auction-house bot, which owns 9 mule characters. None of them are game masters, so the GM filter never touched them. Add more with `ARMORY_BOT_PATTERNS`, or set `ARMORY_HIDE_BOTS=0` to show them all.