Add 3 tutorials (3 files)
Browse Source
3 changed files
with 187 additions and 0 deletions
A
fix-protocol-mismatch-47-48/en.md
+43 -0
A
install-32bit-libraries-cs16-linux/en.md
+81 -0
A
make-server-accept-nonsteam/en.md
+63 -0
fix-protocol-mismatch-47-48/en.md
A
| @@ -0,0 +1,43 @@ | ||
| 1 | +--- | |
| 2 | +title: "Fix: Protocol 48 vs 47 Mismatch (Clients Rejected)" | |
| 3 | +excerpt: "Some clients get 'This server is using a different protocol' because CS 1.6 has two engine protocols, 47 and 48. Understand which client uses which and accept both with dproto." | |
| 4 | +category: "errors" | |
| 5 | +tags: "protocol, dproto" | |
| 6 | +image: "" | |
| 7 | +read_time: "7 min read" | |
| 8 | +--- | |
| 9 | +<p>When a client is rejected with <code>This server is using a different protocol</code> (or the older <code>Server uses different protocol</code>), you are looking at the split between engine <strong>protocol 47</strong> and <strong>protocol 48</strong>. Steam CS 1.6 and current builds speak protocol 48. A population of older non-Steam clients — and some very old builds — still speak protocol 47. A server that only accepts one turns the other away at handshake, before authentication even happens.</p> | |
| 10 | + | |
| 11 | +<h2>1. Confirm it is really a protocol split</h2> | |
| 12 | +<p>The giveaway is that the rejection is selective: some players connect fine, a specific group (usually running an older non-Steam build) cannot, and the message is specifically about <em>protocol</em> — not <code>STEAM validation rejected</code> (that is an auth problem, see <a href="/tutorials/fix-nonsteam-players-cant-join">non-Steam players can't join</a>) and not a version/consistency kick. If everyone is rejected, it is not this — check your engine and <code>sv_lan</code> first.</p> | |
| 13 | +<p>The two protocols map cleanly onto two eras of the client:</p> | |
| 14 | +<table> | |
| 15 | +<thead><tr><th>Protocol</th><th>Who speaks it</th></tr></thead> | |
| 16 | +<tbody> | |
| 17 | +<tr><td>48</td><td>Steam CS 1.6 and current builds (the modern default)</td></tr> | |
| 18 | +<tr><td>47</td><td>Older builds and a slice of older non-Steam clients</td></tr> | |
| 19 | +</tbody> | |
| 20 | +</table> | |
| 21 | +<p>A stock server is built to answer one, so whichever group does not match is turned away at the handshake. The engine decides this before Metamod, AMXX or any auth layer runs, which is why no plugin can rescue it — the fix has to sit at the same low level.</p> | |
| 22 | + | |
| 23 | +<h2>2. The clean answer: accept both protocols</h2> | |
| 24 | +<p>On original HLDS, <strong>dproto</strong> is the component that lets a single server answer both protocol 47 and protocol 48 handshakes, so old and new clients coexist. Install it per <a href="/tutorials/install-dproto">the dproto guide</a>, then enable dual-protocol handling in <code>dproto.cfg</code>. The relevant options control whether the server responds to protocol 47 clients in addition to 48; read the config file that ships with your dproto build for the exact key names, because they have changed between releases and setting a key that does not exist is a silent no-op.</p> | |
| 25 | +<p>The principle to get right: you want the server to <strong>answer both</strong>, not to force everyone onto one. Forcing protocol 47 to modernise the old clients, or forcing 48 to shut them out, both cost you players.</p> | |
| 26 | + | |
| 27 | +<h2>3. On ReHLDS, prefer Reunion</h2> | |
| 28 | +<p>If you run <a href="/tutorials/install-rehlds-on-linux">ReHLDS</a>, you should be using <a href="/tutorials/install-reunion">Reunion</a> rather than dproto for the non-Steam and client-type handling. Reunion, kept current by the same organisation as ReHLDS, is maintained against the modern client landscape and handles the client variety you actually see today. Do not stack dproto on top of ReHLDS+Reunion — pick one auth/protocol layer.</p> | |
| 29 | + | |
| 30 | +<h2>4. The client side</h2> | |
| 31 | +<p>Half of these reports are really "this player has an ancient client". If a single user cannot connect while an entire modern lobby can, the pragmatic fix is on their end: update their CS 1.6 to a current build, which speaks protocol 48. You cannot bend the whole server around one stale install, and after the <a href="/tutorials/fix-25th-anniversary-server-broken">25th Anniversary update</a> the gap between very old builds and current ones widened further.</p> | |
| 32 | +<p>Weigh the two audiences honestly before you decide. If your player base is largely modern Steam and non-Steam clients, accepting protocol 48 only and asking the rare straggler to update is the low-maintenance choice. If you deliberately court the older non-Steam population — common on servers in regions where that client is still dominant — then dual-protocol via dproto is worth the setup, because those players are a real slice of your traffic, not an edge case. There is no universally correct answer; there is the answer that matches who actually plays on your server.</p> | |
| 33 | + | |
| 34 | +<h2>Common errors</h2> | |
| 35 | +<ul> | |
| 36 | +<li><strong>You "fixed" it by forcing protocol 47</strong> — now modern Steam clients are the ones rejected. Answer both instead of forcing one.</li> | |
| 37 | +<li><strong>Edited <code>dproto.cfg</code> but nothing changed</strong> — either the key name is wrong for your dproto version (check the shipped config), or dproto is not actually loaded. Confirm it is active before blaming the setting.</li> | |
| 38 | +<li><strong>dproto and Reunion both installed</strong> — remove one. Two protocol/auth layers conflict and produce exactly these intermittent rejections.</li> | |
| 39 | +<li><strong>Message is about version, not protocol</strong> — <code>Server is enforcing consistency</code> or a build-version kick is a different issue; see <a href="/tutorials/fix-players-timeout-map-change">map-change and consistency problems</a>.</li> | |
| 40 | +</ul> | |
| 41 | + | |
| 42 | +<h2>Verification</h2> | |
| 43 | +<p>Test with two clients: one current Steam build (protocol 48) and one older non-Steam build (protocol 47). Both should reach the server and spawn. In the server console, <code>status</code> should list both without either being dropped at handshake. Watch <code>Log/errors-*.log</code> during the test — no protocol-rejection lines means the server is now answering both handshakes. If only one client type connects, you have forced a single protocol; revisit the dproto config so it responds to both.</p> |
install-32bit-libraries-cs16-linux/en.md
A
| @@ -0,0 +1,81 @@ | ||
| 1 | +--- | |
| 2 | +title: "How to Install the 32-bit Libraries HLDS Needs (lib32, i386)" | |
| 3 | +excerpt: "HLDS is a 32-bit binary and modern 64-bit Linux ships none of its runtime. Here is the exact i386 package set for Debian, Ubuntu, and RHEL, plus how to diagnose which one is missing." | |
| 4 | +category: "installation" | |
| 5 | +tags: "linux, dependencies" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>HLDS, ReHLDS, <code>cs.so</code>, Metamod and every AMXX module are 32-bit (i386) ELF objects. A modern 64-bit Linux install has no reason to carry a 32-bit runtime and does not, so the single most common CS 1.6 install failure is a missing i386 library. This guide is the reference for exactly which packages to install and, more usefully, how to work out which one you are actually missing instead of guessing.</p> | |
| 10 | + | |
| 11 | +<h2>1. The tell-tale error</h2> | |
| 12 | +<p>The most confusing symptom is this:</p> | |
| 13 | +<pre>./hlds_linux: No such file or directory</pre> | |
| 14 | +<p>The file plainly exists — you are staring at it. What is missing is the 32-bit ELF interpreter, <code>/lib/ld-linux.so.2</code>. The kernel cannot find the loader named in the binary's header, and reports that as "No such file or directory". The other family of errors names the library directly:</p> | |
| 15 | +<pre>error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory</pre> | |
| 16 | +<p>Both mean the same thing: install the 32-bit runtime.</p> | |
| 17 | + | |
| 18 | +<h2>2. Enable multiarch (Debian / Ubuntu)</h2> | |
| 19 | +<pre>sudo dpkg --add-architecture i386 | |
| 20 | +sudo apt update</pre> | |
| 21 | +<p>Without <code>--add-architecture i386</code>, apt does not even know the <code>:i386</code> packages exist and refuses to install them.</p> | |
| 22 | + | |
| 23 | +<h2>3. The package set</h2> | |
| 24 | +<p>On current Debian 12 and Ubuntu 22.04/24.04:</p> | |
| 25 | +<pre>sudo apt install -y \ | |
| 26 | + lib32gcc-s1 \ | |
| 27 | + lib32stdc++6 \ | |
| 28 | + libc6:i386 \ | |
| 29 | + libncurses6:i386 \ | |
| 30 | + libcurl4:i386</pre> | |
| 31 | +<table> | |
| 32 | +<thead><tr><th>Package</th><th>Provides</th><th>Symptom if missing</th></tr></thead> | |
| 33 | +<tbody> | |
| 34 | +<tr><td><code>libc6:i386</code></td><td>32-bit glibc + <code>ld-linux.so.2</code></td><td><code>No such file or directory</code></td></tr> | |
| 35 | +<tr><td><code>lib32stdc++6</code></td><td>32-bit libstdc++</td><td><code>libstdc++.so.6: cannot open</code></td></tr> | |
| 36 | +<tr><td><code>lib32gcc-s1</code></td><td>32-bit libgcc_s</td><td><code>libgcc_s.so.1: cannot open</code></td></tr> | |
| 37 | +<tr><td><code>libncurses6:i386</code></td><td>console text UI</td><td>console garbled / <code>libncurses.so.6</code> missing</td></tr> | |
| 38 | +<tr><td><code>libcurl4:i386</code></td><td>HTTP for some AMXX modules/sockets</td><td>module <code>bad load</code></td></tr> | |
| 39 | +</tbody> | |
| 40 | +</table> | |
| 41 | + | |
| 42 | +<h2>4. Older releases use different names</h2> | |
| 43 | +<p>Package names drifted over the years. If apt says a package has no candidate, try the alternate:</p> | |
| 44 | +<ul> | |
| 45 | +<li><code>lib32gcc-s1</code> was <code>lib32gcc1</code> on older Ubuntu/Debian.</li> | |
| 46 | +<li><code>libncurses6:i386</code> may be <code>libncurses5:i386</code> on older releases; some binaries want <code>libtinfo</code> too.</li> | |
| 47 | +<li>On some releases the meta-package <code>libc6-i386</code> is the way glibc's 32-bit files are shipped rather than <code>libc6:i386</code>.</li> | |
| 48 | +</ul> | |
| 49 | + | |
| 50 | +<h2>5. RHEL / CentOS / Rocky / Alma</h2> | |
| 51 | +<p>The i686 packages are the equivalent:</p> | |
| 52 | +<pre>sudo dnf install -y glibc.i686 libstdc++.i686 libgcc.i686 \ | |
| 53 | + ncurses-libs.i686 libcurl.i686</pre> | |
| 54 | + | |
| 55 | +<h2>6. Diagnose exactly what is missing</h2> | |
| 56 | +<p>Do not install packages blindly — ask the binary what it wants. <code>ldd</code> against the 32-bit binary lists every dependency and flags the unresolved ones:</p> | |
| 57 | +<pre>ldd hlds_linux</pre> | |
| 58 | +<p>Any line ending in <code>=> not found</code> is a library you are missing; map the <code>.so</code> name back to a package with the table above. Confirm the binary really is 32-bit while you are there:</p> | |
| 59 | +<pre>file hlds_linux</pre> | |
| 60 | +<p>It must say <em>ELF 32-bit LSB executable, Intel 80386</em>. If you are debugging a module rather than the engine, point <code>ldd</code> at it:</p> | |
| 61 | +<pre>ldd cstrike/dlls/cs.so | |
| 62 | +ldd cstrike/addons/amxmodx/dlls/amxmodx_mm_i386.so</pre> | |
| 63 | +<p>This is how you catch the case where the engine starts fine but one AMXX module reports <code>bad load</code> — that module has a 32-bit dependency the engine itself did not need.</p> | |
| 64 | + | |
| 65 | +<h2>Why 32-bit at all, in 2026?</h2> | |
| 66 | +<p>There is no 64-bit build of the Half-Life engine. HLDS, ReHLDS, ReGameDLL, Metamod and every AMXX module are compiled for i386 and always have been — the whole plugin ecosystem is 32-bit, and a 64-bit rebuild would break binary compatibility with thousands of existing modules. So the answer is not "port it to 64-bit", it is "install the 32-bit runtime". This is why <code>file</code> on any part of the stack must always report <em>Intel 80386</em>; a 64-bit object anywhere in the chain is a mistake, not an upgrade.</p> | |
| 67 | + | |
| 68 | +<h2>A note on the Steam runtime</h2> | |
| 69 | +<p>SteamCMD itself is also 32-bit and needs the same <code>libc6:i386</code> loader. If <code>steamcmd.sh</code> fails before it even downloads anything — complaining it cannot find a 32-bit interpreter — it is the identical missing-i386 problem, fixed by the same package set. Once the runtime is in place, both SteamCMD and the game server it installs will run.</p> | |
| 70 | + | |
| 71 | +<h2>Common errors</h2> | |
| 72 | +<ul> | |
| 73 | +<li><strong>Installed the packages, still <code>No such file or directory</code></strong> — you installed the 64-bit versions. Confirm the <code>:i386</code> (or <code>.i686</code>) suffix; the plain package is the wrong architecture.</li> | |
| 74 | +<li><strong><code>E: Unable to locate package lib32gcc-s1</code></strong> — you skipped <code>dpkg --add-architecture i386</code> and <code>apt update</code>, or you are on a release that names it <code>lib32gcc1</code>.</li> | |
| 75 | +<li><strong>One module fails, engine is fine</strong> — run <code>ldd</code> on that module; it needs a 32-bit library (often <code>libcurl4:i386</code> for sockets/HTTP modules) the engine does not.</li> | |
| 76 | +<li><strong>Everything resolves in <code>ldd</code> but it still won't start</strong> — the binary itself is 64-bit or corrupt. Check with <code>file</code>; re-download if it is not <em>Intel 80386</em>.</li> | |
| 77 | +</ul> | |
| 78 | + | |
| 79 | +<h2>Verification</h2> | |
| 80 | +<pre>ldd hlds_linux | grep -i "not found"</pre> | |
| 81 | +<p>No output means every dependency resolves. Start the server; it should reach a map instead of dying at load. Once the runtime is in place, the rest of the stack — <a href="/tutorials/install-rehlds-on-linux">ReHLDS</a>, <a href="/tutorials/install-regamedll-cs16">ReGameDLL</a>, Metamod and AMXX — all share these same 32-bit libraries, so this is a one-time fix per host.</p> |
make-server-accept-nonsteam/en.md
A
| @@ -0,0 +1,63 @@ | ||
| 1 | +--- | |
| 2 | +title: "How to Make Your Server Accept Non-Steam Players" | |
| 3 | +excerpt: "Let non-Steam CS 1.6 clients connect: Reunion on ReHLDS or dproto on HLDS, the mandatory SteamIdHashSalt, and how admin identification changes when SteamIDs are not real." | |
| 4 | +category: "installation" | |
| 5 | +tags: "non-steam, reunion" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>Out of the box a CS 1.6 server validates clients against Steam and rejects non-Steam ("no-Steam") builds. Accepting them is a deliberate choice: you install a connection-layer plugin that answers the validation itself and assigns each non-Steam player a SteamID. There are two, and which one you use depends on your engine: <strong>Reunion</strong> on <a href="/tutorials/install-rehlds-on-linux">ReHLDS</a>, <strong>dproto</strong> on original HLDS. Do not run both.</p> | |
| 10 | + | |
| 11 | +<h2>1. Pick the right one for your engine</h2> | |
| 12 | +<ul> | |
| 13 | +<li><strong>ReHLDS → Reunion.</strong> Reunion is written for ReHLDS and is the current, maintained choice. This is what you should be running.</li> | |
| 14 | +<li><strong>Original Valve HLDS → dproto.</strong> dproto predates ReHLDS and still works on stock engines. If you are on stock HLDS in 2026, the better move is to switch to ReHLDS + Reunion.</li> | |
| 15 | +</ul> | |
| 16 | +<p>Both are Metamod plugins, so you need a working Metamod-r first — verify with <code>meta list</code>.</p> | |
| 17 | + | |
| 18 | +<h2>2. Install Reunion (ReHLDS)</h2> | |
| 19 | +<p>Reunion ships as a Metamod plugin plus a config. Place the plugin binary under the addons tree and register it in Metamod's plugin list:</p> | |
| 20 | +<pre>cstrike/addons/reunion/reunion_mm_i386.so <-- the plugin | |
| 21 | +cstrike/addons/reunion/reunion.cfg <-- its config</pre> | |
| 22 | +<p>Add it to <code>cstrike/addons/metamod/plugins.ini</code> above AMXX:</p> | |
| 23 | +<pre>linux addons/reunion/reunion_mm_i386.so</pre> | |
| 24 | + | |
| 25 | +<h2>3. Set the mandatory SteamIdHashSalt</h2> | |
| 26 | +<p>This is the step people miss, and Reunion will not load without it. In <code>reunion.cfg</code>:</p> | |
| 27 | +<pre>SteamIdHashSalt = your_long_random_salt_at_least_16_chars</pre> | |
| 28 | +<p><strong>The salt must be at least 16 characters.</strong> Shorter and Reunion refuses to start, which shows up as Reunion missing from <code>meta list</code>. The salt is what turns a non-Steam player's identity into a stable <code>STEAM_ID</code>-style string — change it later and every non-Steam player's ID changes with it, which resets their stats and their admin access. Set it once and never touch it.</p> | |
| 29 | + | |
| 30 | +<h2>4. Decide who is allowed in</h2> | |
| 31 | +<p>Reunion's config controls which client types are accepted — Steam, non-Steam (Steam emulators / Revolution Emulator), or both. Configure the authentication providers in <code>reunion.cfg</code> to match your policy. The common setups are "both Steam and non-Steam" (maximum audience) or "non-Steam only" (a purely no-Steam community). Read the shipped config's comments for the exact provider keys in your build rather than guessing.</p> | |
| 32 | + | |
| 33 | +<h2>5. Fix admin identification</h2> | |
| 34 | +<p>This is the real operational consequence. A non-Steam player's SteamID is generated from their name and your salt, not issued by Valve — so it is only as trustworthy as the name is unique. For admins on a non-Steam-friendly server you have two choices:</p> | |
| 35 | +<ul> | |
| 36 | +<li><strong>Name + password auth</strong> in <code>users.ini</code> — the reliable option for non-Steam admins:</li> | |
| 37 | +</ul> | |
| 38 | +<pre>; users.ini | |
| 39 | +"AdminName" "adminpassword" "abcdefghijklmnopqrstu" "a"</pre> | |
| 40 | +<p>with the matching flags including the "requires password" flag, so an impostor with the same name but no password gets nothing. Relying on the generated SteamID alone for admin access on a non-Steam server is how admin gets stolen.</p> | |
| 41 | + | |
| 42 | +<h2>Common errors</h2> | |
| 43 | +<ul> | |
| 44 | +<li><strong>Reunion missing from <code>meta list</code></strong> — the <code>SteamIdHashSalt</code> is unset or shorter than 16 characters, or the <code>plugins.ini</code> path/architecture is wrong (Linux line must point at the <code>.so</code>).</li> | |
| 45 | +<li><strong>Non-Steam clients still get <code>STEAM validation rejected</code></strong> — Reunion/dproto is not actually loading, or you left VAC/secure mode fighting it. See <a href="/tutorials/fix-steam-validation-rejected">the validation-rejected fix</a>.</li> | |
| 46 | +<li><strong>Running Reunion and dproto together</strong> — they both answer validation and conflict. Pick one.</li> | |
| 47 | +<li><strong>All non-Steam players share one SteamID</strong> — the salt is empty or the provider config is collapsing identities. Set a proper salt and correct providers.</li> | |
| 48 | +<li><strong>Admins lost access after a config change</strong> — you changed the salt, which changed every generated ID. Move admins to name+password auth.</li> | |
| 49 | +</ul> | |
| 50 | + | |
| 51 | +<h2>Verification</h2> | |
| 52 | +<p>Restart and confirm the plugin loaded:</p> | |
| 53 | +<pre>meta list</pre> | |
| 54 | +<p>Reunion (or dproto) must show as <code>RUN</code>. Then connect with an actual non-Steam client and, in the server console, run <code>status</code> — the player must appear with a <code>STEAM_</code> ID, not be rejected. Have that player disconnect and reconnect: their ID must stay the same across sessions (this is what the salt guarantees). Finally, log an admin in via name+password and confirm <code>amx_who</code> shows their flags. When a non-Steam player connects, keeps a stable ID, and a non-Steam admin authenticates, the setup is complete.</p> | |
| 55 | + | |
| 56 | +<h2>What accepting non-Steam actually costs you</h2> | |
| 57 | +<p>It is worth being clear-eyed about the trade, because it is not free. A Valve-issued SteamID is cryptographically tied to an account; a Reunion-generated ID is a hash of a name and your salt, so on a non-Steam-friendly server, identity is roughly "whoever types this name". That has three practical consequences you should plan for from the start:</p> | |
| 58 | +<ul> | |
| 59 | +<li><strong>Stats and reserved slots keyed on SteamID are spoofable</strong> by name. If you run a ranking or shop system, expect people to impersonate each other's names to claim progress. Password-gating the things that matter is the only real defence.</li> | |
| 60 | +<li><strong>Bans by SteamID are weaker</strong> — a banned non-Steam player changes their name and returns with a new ID. Non-Steam servers lean harder on IP bans as a result; see your <a href="/plugins/csb-ban-manager">ban manager</a> for combining the two.</li> | |
| 61 | +<li><strong>Admin must be password-based</strong>, as above, because SteamID-only admin is trivially stolen.</li> | |
| 62 | +</ul> | |
| 63 | +<p>None of this is a reason not to accept non-Steam players — for most CS 1.6 communities it is where the audience is. It is a reason to build your admin, ban and stats systems assuming identity is weak, rather than discovering it the first time someone wears an admin's name.</p> | |
| 0 | 64 |









