# Running a 2009scape Server on Arch Linux (LAN play) A step-by-step guide to compiling and running the game server on an Arch Linux machine, then connecting to it from another PC on your network (e.g. a gaming PC in the same house). This targets a **private/LAN setup for yourself** — it deliberately skips the database (`use_auth`/`persist_accounts` stay off), which is the simplest way to get playing. See [the notes on persistence](#optional-persistence-and-accounts-mysql) if you want saved accounts. > Reminder: the upstream project only supports its own live server. This guide is for > running your own copy locally and is assembled from how this repo actually works — see > [`ARCHITECTURE.md`](ARCHITECTURE.md) and the root [`../README.md`](../README.md). ## 0. What you'll end up with - The **game server** running on your Arch machine (headless, in a terminal). - It listens on TCP port **`43594 + world_id`** → **43595** with the default `world_id = 1`. - Your **gaming PC** runs the 2009scape **client** (a separate download) pointed at the Arch machine's LAN IP. ## 1. Install prerequisites (Arch) The build needs **JDK 11 specifically** — not a newer JDK (the project targets Java 11 and newer versions break the build). You also need **git** and **git-lfs** (the game cache is stored via Git LFS). ```bash sudo pacman -S --needed jdk11-openjdk git git-lfs # optional: tmux, if you want to use the run script's -x fancy session mode sudo pacman -S --needed tmux ``` You do **not** need Maven installed — the repo ships the Maven wrapper (`Server/mvnw`). If you have multiple JDKs installed, point the default at 11 for this shell: ```bash archlinux-java status # list installed JVMs sudo archlinux-java set java-11-openjdk java -version # should report 11.x ``` Enable Git LFS once for your user: ```bash git lfs install ``` ## 2. Get the code and pull the cache If you haven't cloned yet (upstream is on GitLab): ```bash git clone https://gitlab.com/2009scape/2009scape.git cd 2009scape ``` If you already have this repo, just make sure the LFS-backed cache is actually present (this pulls the real binary cache files under `Server/data/cache/`, which are LFS pointers until fetched): ```bash git lfs pull ``` You can sanity-check the cache came down (files should be MB-sized, not tiny pointer text): ```bash du -sh Server/data/cache ``` ## 3. Configure the server for LAN play The server config is `Server/worldprops/default.conf` (TOML). The defaults are already set up for a no-database local run: - `use_auth = false` — any password is accepted at login. - `persist_accounts = false` — no database required. - `noauth_default_admin = true` — you log in as an admin (handy for testing). - `world_id = "1"` — so the game port is **43595**. - `enable_bots = true` — the world spawns AI player bots (see [`BOT_SCRIPTING.md`](BOT_SCRIPTING.md)); set to `false` if you'd rather have an empty world. **You generally do not need to change anything in the config for LAN play.** The one field people assume they must change — `msip` — is the **management-server** address (used by the separate world-list/management backend), *not* the address the game client connects to. For a single self-hosted world you can leave `msip = "127.0.0.1"`. Two things you *may* want to set: - **`secret_key`** — the client sends this on login and it **must match** the server's value or the connection is refused. The default is `"2009scape_development"`. If your client uses a different key, make them match here. - **`new_player_location` / `home_location`** — where you spawn; fine to leave default. ## 4. Build and run From the repo root, the helper scripts wrap the Maven wrapper. The simplest path: ```bash ./run ``` `./run` does an incremental build and then starts the server. Other useful invocations: ```bash ./run -r # force a clean rebuild, then run (use after pulling updates) ./run -t # run the test suite only, don't start the server ./run -h # show all options ./build -qgc # clean build only (skip tests), no run ``` The **first build takes a while** (it compiles thousands of Kotlin/Java files). Grab a coffee. Subsequent runs are fast. Under the hood this runs the fat jar with: ``` cd Server && java -Dnashorn.args=--no-deprecation-warning -jar builddir/server.jar ``` The server runs headless in your terminal. You'll see log lines ending with something like `2009Scape started in milliseconds.` and `Starting networking...`. It reads simple commands on stdin — type `stop` to shut it down cleanly (or `help` for the list). > If you build manually with Maven instead of the scripts, run `sh mvnw clean` first — the > clean phase installs bundled libraries (`ConstLib`, `PrimitiveExtensions`) from > `Server/libs/` into your local Maven repo, without which compilation fails. ### Memory The server is comfortable in default JVM memory for a small LAN world. If you enable `preload_map = true` (smoother ticks) it needs ~2 GB more RAM; give the JVM more heap by editing the `java` invocation in the `run` script, e.g. add `-Xmx4g`. ## 5. Find the server's LAN IP On the Arch machine: ```bash ip -4 addr show | grep inet ``` Note the LAN address (typically `192.168.x.y` or `10.x.y.z`). That's what the gaming PC will connect to. Example used below: `192.168.1.50`. ## 6. Open the firewall (if one is running) Arch has no firewall enabled by default, but if you run one, allow the game port (**43595** for world 1). Examples: ```bash # firewalld sudo firewall-cmd --add-port=43595/tcp --permanent && sudo firewall-cmd --reload # ufw sudo ufw allow 43595/tcp # nftables (add to your ruleset) # tcp dport 43595 accept ``` If you also enabled the browser WebSocket transport, open its port too (default `53594 + world_id` = **53595**). ## 7. Connect from the gaming PC The **client is a separate program** from this server repo — download the launcher/client from the 2009scape site or use whichever client you already have. In the client's server configuration, point it at the Arch machine instead of the public server: - **Server address / IP:** the Arch machine's LAN IP, e.g. `192.168.1.50` - **Port:** `43595` (i.e. `43594 + world_id`) - **Secret key:** must match `secret_key` in `default.conf` (default `2009scape_development`) How you set these depends on the client build — commonly an in-launcher field, a settings file, or a `worlds`/`serverlist` entry. Look for where the client stores the world IP/port. Then log in with any username; with `use_auth = false` the password is not checked, and with `noauth_default_admin = true` you'll have admin privileges (try `::` commands in chat). ## 8. Quick verification - On the server machine, confirm it's listening: ```bash ss -tlnp | grep 43595 ``` - From the gaming PC, confirm reachability (PowerShell): ```powershell Test-NetConnection 192.168.1.50 -Port 43595 ``` or from any Linux box: `nc -vz 192.168.1.50 43595`. If the port test succeeds but login fails, the usual culprit is a **`secret_key` mismatch** between client and server. ## Optional: persistence and accounts (MySQL) The no-database setup above forgets account-level data (credits, playtime) on restart — but note character save data (stats, inventory) is handled separately and still saves to `Server/data/players/`. If you want real authenticated accounts and persisted account data, set in `default.conf`: ```properties use_auth = true persist_accounts = true ``` …and provide a MySQL/MariaDB database matching the `[database]` block (`database_name`, `_username`, `_password`, `_address`, `_port`). On Arch: ```bash sudo pacman -S --needed mariadb sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql sudo systemctl enable --now mariadb ``` Then create the database and import the schema shipped in the repo: ```bash sudo mariadb -e "CREATE DATABASE global;" sudo mariadb global < Server/db_exports/global.sql # optional test account: sudo mariadb global < Server/db_exports/testuser.sql ``` Adjust `database_username`/`database_password` in `default.conf` to match a MySQL user you create. (For quick LAN use, keeping the database off is simpler.) ### Docker alternative If you'd rather not manage a local MariaDB, the repo has a Docker path (server + MySQL) — see the **Docker** section of the root [`../README.md`](../README.md). It uses `mysql.env` and a `config/default.conf` you copy from `Server/worldprops/default.conf`. ## Troubleshooting | Symptom | Likely cause / fix | |---------|--------------------| | Build fails immediately with weird Kotlin/Java errors | Wrong JDK. Ensure `java -version` is **11** (`sudo archlinux-java set java-11-openjdk`). | | Build fails about missing `ConstLib`/`primextends` | You built without a clean. Run `./build -qgc` (or `sh mvnw clean` in `Server/`). | | Cache errors / tiny cache files | LFS not pulled. Run `git lfs install` then `git lfs pull`. | | `Port 43595 is already in use` | Another server instance is running, or change `world_id`. | | Client can't reach the server | Firewall on the Arch box, wrong LAN IP, or client pointed at the wrong port. Verify with `ss`/`nc` (step 8). | | Connects but login refused | `secret_key` mismatch between client and `default.conf`. | | World feels crowded with bots | Set `enable_bots = false` (and/or `max_adv_bots = 0`) in `default.conf`. |