Unknown ❤ RESPAWN.ZAFEST.RO | VIP FREE | FREE FOR ALL ❤ 0/32
Romania XPlayZM.CSBlackDevil.COM # Zombie Plague UltimateX [ Respawn + FDL + VIP 22-12PM + POINTS] ® 15/32
Sunucu tanitimi

Add 6 tutorials (6 files)

Browse Source
Daemon666 committed parent 78b0510b12 commit 1262470489096cbd1341ac10bed8d00ac17e63d7
6 changed files with 356 additions and 0 deletions
+55 -0 amxbans-web-panel/en.md A
@@ -0,0 +1,55 @@
1 +---
2 +title: "Setting Up the AMXBans Web Panel"
3 +excerpt: "How to connect the AMXBans web admin panel to your MySQL ban database, configure config.php, create the first web admin, and keep the plugin and site in sync."
4 +category: "administration"
5 +tags: "amxbans, web"
6 +image: ""
7 +read_time: "8 min read"
8 +---
9 +<p>AMXBans stores bans in a MySQL database, and its web panel is the browser front-end to that database — a place to review, add and lift bans, manage admins, and show players a public ban list without touching the game console. Getting it running is mostly a matter of pointing the web files at the same database your in-game <a href="/tutorials/install-amxbans">AMXBans plugin</a> already writes to. This assumes the plugin side is installed and logging bans; the panel is the second half.</p>
10 +
11 +<h2>1. Prerequisites</h2>
12 +<p>You need three things in place first:</p>
13 +<ul>
14 +<li>A working AMXBans plugin on the server, already connected to a MySQL database and recording bans. If bans are not landing in the database, fix that before the web side — the panel only shows what the plugin writes.</li>
15 +<li>A web host running PHP and MySQL that can reach the same database (or a copy of it).</li>
16 +<li>The MySQL host, database name, username and password the plugin uses.</li>
17 +</ul>
18 +
19 +<h2>2. Create or reuse the database and import the schema</h2>
20 +<p>The panel and the plugin must share one database. If you have not created it yet, do so and grant a dedicated user access:</p>
21 +<pre>CREATE DATABASE amxbans CHARACTER SET utf8;
22 +CREATE USER 'amxbans'@'%' IDENTIFIED BY 'a-long-password';
23 +GRANT ALL PRIVILEGES ON amxbans.* TO 'amxbans'@'%';
24 +FLUSH PRIVILEGES;</pre>
25 +<p>AMXBans ships an SQL schema file with its web package; import it once so the ban, admin and server tables exist:</p>
26 +<pre>mysql -u amxbans -p amxbans &lt; amxbans.sql</pre>
27 +<p>If the plugin already created its tables, do not re-import over live data — the schema is the same one both halves use.</p>
28 +
29 +<h2>3. Upload the web files and edit config.php</h2>
30 +<p>Copy the panel's web directory into your web root, then open its main configuration file (commonly <code>config.php</code> in an <code>includes/</code> folder) and fill in the database connection and a security salt. The exact variable names come from the version you downloaded, but they always cover the same fields:</p>
31 +<pre>$config['sql_host'] = 'localhost';
32 +$config['sql_user'] = 'amxbans';
33 +$config['sql_pass'] = 'a-long-password';
34 +$config['sql_db'] = 'amxbans';
35 +$config['sql_prefix'] = 'amx_';
36 +$config['salt'] = 'a-random-16-plus-char-string';</pre>
37 +<p>The table prefix must match what the plugin uses, or the panel connects but shows no bans. Set the salt to a long random value and keep it secret — it protects stored web-admin passwords.</p>
38 +
39 +<h2>4. Run the installer and create the first admin</h2>
40 +<p>Most AMXBans web editions include a one-time setup page (often under an <code>install/</code> directory) that verifies the database connection and lets you create the first web administrator. Complete it, then <strong>delete or rename the install directory</strong> — leaving it reachable is a standing security hole that lets anyone re-run setup and seize the panel. Log in with the admin account you just created and confirm the dashboard loads.</p>
41 +
42 +<h2>5. Link the plugin and the panel</h2>
43 +<p>For bans issued in-game to appear on the site and vice versa, the plugin's SQL config must point at the same database and prefix as <code>config.php</code>. AMXBans keeps this in its own config under <code>addons/amxmodx/configs/</code> (the SQL section of the AMXBans config). Match the host, user, password, database and prefix on both sides exactly. Once they agree, a ban you place with <code>amx_ban</code> shows up in the panel within a refresh, and a ban you lift on the site stops blocking the player in-game. If you want a lighter, self-contained alternative to the whole AMXBans stack, the <a href="/plugins/csb-ban-manager">CSB Ban Manager</a> keeps bans without a separate web install.</p>
44 +
45 +<h2>Common errors</h2>
46 +<ul>
47 +<li><strong>Panel loads but shows zero bans</strong> — the table prefix or database name in <code>config.php</code> does not match what the plugin writes to. Align both configs.</li>
48 +<li><strong><code>Access denied for user</code> on the site</strong> — the MySQL user cannot connect from the web host. Check the user's allowed host (<code>'amxbans'@'%'</code> vs <code>localhost</code>) and the password.</li>
49 +<li><strong>Bans placed in-game never appear online</strong> — the plugin is using a different database (or SQLite) than the panel. Point both at the one MySQL database.</li>
50 +<li><strong>Cannot log in to the panel</strong> — the salt was changed after the admin password was hashed, invalidating it. Keep the salt fixed once admins exist, or reset the admin.</li>
51 +<li><strong>Anyone can re-run setup</strong> — you left the install directory in place. Remove it.</li>
52 +</ul>
53 +
54 +<h2>Verification</h2>
55 +<p>Place a test ban in-game with <code>amx_ban</code>, refresh the panel, and confirm the ban appears with the correct SteamID, admin name and duration. Then lift it from the web panel and verify the player can reconnect. Finally, load the public ban-list page in a browser to confirm it renders for visitors. If in-game and web bans stay out of sync, the two configs are pointing at different databases — the single most common AMXBans mistake.</p>
+70 -0 block-udp-flood-iptables/en.md A
@@ -0,0 +1,70 @@
1 +---
2 +title: "Blocking UDP Floods on a CS 1.6 Server with iptables and ipset"
3 +excerpt: "Rate-limit the game port, absorb A2S query floods, and maintain a fast drop list with ipset — plus the limits of host-level filtering against real volumetric attacks."
4 +category: "security"
5 +tags: "iptables, ddos"
6 +image: ""
7 +read_time: "8 min read"
8 +---
9 +<p>A CS 1.6 server listens on UDP 27015, and UDP is trivially spoofable, so floods are a fact of life: query-spam that pins your CPU, connection floods that fill slots, and outright volumetric attacks. Host-level <code>iptables</code> with <code>ipset</code> will not stop a large volumetric DDoS — that has to be scrubbed upstream — but it handles the everyday junk that would otherwise degrade your server, cheaply and without touching the game. Here is a practical filter set.</p>
10 +
11 +<blockquote>Be careful with per-IP limits: many legitimate players sit behind the same carrier NAT or share a home connection, so set thresholds generously and watch for false positives before tightening.</blockquote>
12 +
13 +<h2>1. Rate-limit the game port with hashlimit</h2>
14 +<p>The <code>hashlimit</code> match tracks packet rates per source IP without a separate rule per address. Cap how fast any single IP may hammer the game port:</p>
15 +<pre>iptables -A INPUT -p udp --dport 27015 \
16 + -m hashlimit \
17 + --hashlimit-name cs_flood \
18 + --hashlimit-mode srcip \
19 + --hashlimit-above 40/sec \
20 + --hashlimit-burst 60 \
21 + -j DROP</pre>
22 +<p>This drops packets from any IP exceeding 40/sec (after a 60-packet burst). Tune the numbers to your traffic — legitimate gameplay is well under that, but a busy query period can spike, so measure before you clamp hard.</p>
23 +
24 +<h2>2. Absorb A2S_INFO query floods</h2>
25 +<p>Server-browser queries (A2S_INFO / A2S_PLAYER) are small requests that trigger larger replies, which is why they get abused for both CPU exhaustion and reflection. Rate-limit query-sized inbound packets separately from gameplay so a query flood cannot starve real players:</p>
26 +<pre>iptables -A INPUT -p udp --dport 27015 -m length --length 0:32 \
27 + -m hashlimit \
28 + --hashlimit-name cs_query \
29 + --hashlimit-mode srcip \
30 + --hashlimit-above 5/sec \
31 + --hashlimit-burst 10 \
32 + -j DROP</pre>
33 +<p>Small packets are almost always queries or connection attempts; capping them per IP kills query-spam while leaving in-game traffic (larger packets) alone.</p>
34 +
35 +<h2>3. Maintain a drop list with ipset</h2>
36 +<p>Matching against thousands of blocked IPs one rule at a time is slow. <code>ipset</code> stores them in a hash the kernel checks in near-constant time. Create a timed blacklist and drop it at the top of INPUT:</p>
37 +<pre>ipset create cs_blacklist hash:ip timeout 3600
38 +iptables -I INPUT -m set --match-set cs_blacklist src -j DROP</pre>
39 +<p>Now any process that detects an abuser can ban it for an hour with one command, and the entry expires itself:</p>
40 +<pre>ipset add cs_blacklist 203.0.113.7 timeout 3600</pre>
41 +<p>Wire your abuse detection (a log watcher, or a hashlimit LOG rule) to feed this set. The <code>timeout</code> means you never have to remember to unban.</p>
42 +
43 +<h2>4. Drop obviously invalid traffic</h2>
44 +<p>Cheap rules that shed junk before it reaches the game:</p>
45 +<pre># invalid/malformed conntrack state
46 +iptables -A INPUT -p udp --dport 27015 -m state --state INVALID -j DROP
47 +# traffic to ports you do not run
48 +iptables -A INPUT -p udp --dport 27016:65535 -j DROP</pre>
49 +<p>Keep these narrow — a rule that is too broad will drop legitimate players. Only block ranges you genuinely do not use.</p>
50 +
51 +<h2>5. Make it survive a reboot</h2>
52 +<p>iptables and ipset rules are in-memory. Persist them so a reboot does not drop your protection:</p>
53 +<pre>ipset save &gt; /etc/ipset.rules
54 +iptables-save &gt; /etc/iptables/rules.v4</pre>
55 +<p>Restore <code>ipset</code> <em>before</em> iptables on boot, because the iptables rule references the set — if the set does not exist yet, the rule fails to load.</p>
56 +
57 +<h2>Troubleshooting</h2>
58 +<ul>
59 +<li><strong>Legit players get dropped during busy periods</strong> — your <code>--hashlimit-above</code> is too aggressive, or several players share one NAT IP. Raise the threshold and burst.</li>
60 +<li><strong>Rule fails: "Set cs_blacklist doesn't exist"</strong> — the iptables rule loaded before the ipset. Create/restore the set first.</li>
61 +<li><strong>Server still lags under attack</strong> — this is volumetric and saturating your uplink; host filtering cannot help once the pipe is full. You need upstream scrubbing — see <a href="/tutorials/ddos-protected-hosting">DDoS-protected hosting</a>.</li>
62 +<li><strong>Rules vanish after reboot</strong> — you did not persist them, or ipset restored after iptables. Fix the boot order.</li>
63 +<li><strong>Everything is blocked</strong> — a broad DROP range caught the game port itself. Check your port ranges against <a href="/tutorials/cs16-server-firewall-ports">the CS 1.6 port list</a>.</li>
64 +</ul>
65 +
66 +<h2>Verification</h2>
67 +<p>Watch the counters while under load — a working rule shows its packet count climbing:</p>
68 +<pre>iptables -L INPUT -v -n --line-numbers
69 +ipset list cs_blacklist</pre>
70 +<p>Generate a controlled burst of queries from a test host and confirm the query-limit rule's counter rises while a normal player still connects and plays without choke. If the DROP counters stay flat during an obvious flood, your match conditions are not catching the traffic — recheck the port and packet-length filters. For attacks that saturate the link regardless, escalate to <a href="/tutorials/ddos-protected-hosting">upstream DDoS protection</a>.</p>
+20 -0 cs16-binds-and-aliases/en.md A
@@ -0,0 +1,20 @@
1 +---
2 +title: "Binding Keys and Aliases in CS 1.6"
3 +excerpt: "The bind syntax and key names, chaining commands with semicolons, +/- hold commands, building buy binds, and toggle aliases that flip state each press."
4 +category: "client"
5 +tags: "binds, config"
6 +image: ""
7 +read_time: "8 min read"
8 +---
9 +<p>Binds and aliases are what separate a configured CS 1.6 player from someone fumbling through the buy menu every round. A bind maps a key to one or more commands; an alias names a sequence of commands so you can reuse or toggle it. Both are just console commands, so they belong in your <a href="/tutorials/cs16-autoexec-cfg">autoexec.cfg</a>. This covers the syntax, the traps, and the two patterns you will actually use: buy binds and toggles.</p><h2>1. The bind syntax</h2><p>The form is <code>bind &quot;key&quot; &quot;command&quot;</code>. The command in quotes runs when the key is pressed:</p><pre>bind "f" "+use"
10 +bind "r" "+reload"
11 +bind "t" "+voicerecord"</pre><p>Type <code>bind</code> in the console with just a key to see what it is currently bound to, and <code>unbind &quot;key&quot;</code> to clear one. <code>unbindall</code> wipes everything &mdash; useful to start clean, but only if your autoexec then rebinds a full set, or you will be left with a keyboard that does nothing.</p><h2>2. Key names you need to know</h2><p>Keys have specific names; guessing wrong is a common reason a bind "does nothing":</p><ul><li>Letters and digits are themselves: <code>a</code>, <code>5</code>.</li><li>Mouse buttons: <code>mouse1</code>, <code>mouse2</code>, <code>mouse3</code> (wheel click), <code>mouse4</code>, <code>mouse5</code>, and <code>mwheelup</code> / <code>mwheeldown</code>.</li><li>Numpad keys are prefixed <code>kp_</code>: <code>kp_end</code> (1), <code>kp_downarrow</code> (2), <code>kp_home</code> (7), <code>kp_ins</code> (0), and so on &mdash; these are the classic buy-bind keys.</li><li>Named keys: <code>space</code>, <code>ctrl</code>, <code>shift</code>, <code>alt</code>, <code>enter</code>, <code>tab</code>, <code>semicolon</code>, <code>uparrow</code>.</li></ul><h2>3. Chaining commands with semicolons</h2><p>Multiple commands on one key are separated by semicolons, inside the quotes:</p><pre>bind "kp_end" "buy primammo; buy secammo"
12 +bind "h" "say Nice shot!; slot1"</pre><p>Every command runs in order on the single keypress. This is the foundation of buy binds &mdash; a whole loadout on one key.</p><h2>4. Build a buy bind</h2><p>The buy menu accepts direct <code>buy</code> commands, so you can bind a full kit. Weapon aliases like <code>ak47</code>, <code>m4a1</code>, <code>deagle</code>, <code>vesthelm</code>, <code>hegrenade</code>, <code>flashbang</code> work regardless of team where the item exists:</p><pre>// full-buy CT on one key
13 +bind "kp_downarrow" "buy m4a1; buy deagle; buy vesthelm; buy hegrenade; buy flashbang; buy flashbang; buy smokegrenade; buy defuser"
14 +// full-buy T
15 +bind "kp_leftarrow" "buy ak47; buy deagle; buy vesthelm; buy hegrenade; buy flashbang; buy flashbang; buy smokegrenade"</pre><p>Buys that do not apply (a defuser as T, an item you cannot afford) are simply ignored, so a slightly over-specified bind is harmless. Keep two keys &mdash; one CT kit, one T kit &mdash; and you rebuy in a single press during <a href="/tutorials/mp-cvars-reference">freezetime</a>.</p><h2>5. The +/- hold commands</h2><p>Commands starting with <code>+</code> stay active while the key is held and release on a matching <code>-</code>. The engine handles the release automatically when you bind a <code>+</code> command:</p><pre>bind "space" "+jump"
16 +bind "shift" "+speed" // walk while held
17 +bind "mouse3" "+duck"</pre><p>Do not bind the <code>-</code> half yourself; binding <code>+duck</code> to a key gives you both press and release for free. Manually mixing <code>+</code> and <code>-</code> on the same key is how people end up permanently crouched.</p><h2>6. Toggle aliases that flip each press</h2><p>An alias names a command sequence; two aliases that redefine a third let you flip state on each press. The classic is a crouch-toggle or a hand-switch:</p><pre>alias "togglehand" "hand_on"
18 +alias "hand_on" "cl_righthand 1; alias togglehand hand_off"
19 +alias "hand_off" "cl_righthand 0; alias togglehand hand_on"
20 +bind "c" "togglehand"</pre><p>The trick: each half redefines <code>togglehand</code> to point at the other half, so pressing <code>c</code> alternates between right and left hand. The same pattern toggles a nightvision, a bomb-timer bind, or a "clean HUD" screenshot mode. Put all of this in <a href="/tutorials/cs16-autoexec-cfg">autoexec.cfg</a> so it loads every launch.</p><h2>Common errors</h2><ul><li><strong>Bind does nothing</strong> &mdash; wrong key name (e.g. <code>mwheel_up</code> instead of <code>mwheelup</code>, or <code>numpad1</code> instead of <code>kp_end</code>). Verify the name.</li><li><strong>Only the first command runs</strong> &mdash; you split commands with something other than a semicolon, or the whole chain is not wrapped in one pair of quotes.</li><li><strong>Stuck crouched or walking</strong> &mdash; you bound both a <code>+</code> and a <code>-</code> command by hand. Bind only the <code>+</code> half.</li><li><strong>Toggle alias only works once</strong> &mdash; each alias half must redefine the toggle name to the other half; a missing <code>alias togglehand ...</code> line breaks the flip.</li><li><strong>Binds vanish next launch</strong> &mdash; you set them in the console but did not save them to autoexec, and <code>config.cfg</code> did not capture them. Put them in <a href="/tutorials/cs16-autoexec-cfg">autoexec.cfg</a>.</li></ul><h2>Verification</h2><p>Bind a test key, then read it back in the console:</p><pre>bind kp_downarrow</pre><p>It should echo the full command string you assigned. Join a server, hit your buy key during freezetime, and confirm the loadout appears in one press. Test the toggle key twice and confirm the state alternates. Once your set works, save it into <a href="/tutorials/cs16-autoexec-cfg">autoexec.cfg</a> so it survives every launch.</p>
+61 -0 cs16-enable-console/en.md A
@@ -0,0 +1,61 @@
1 +---
2 +title: "How to Enable the Developer Console in CS 1.6"
3 +excerpt: "Three ways to turn on the CS 1.6 developer console — the in-game keyboard option, the -console launch option, and a toggleconsole bind — plus why it stays disabled."
4 +category: "client"
5 +tags: "console, settings"
6 +image: ""
7 +read_time: "6 min read"
8 +---
9 +<p>The developer console is where you do everything that matters in CS 1.6: connect to servers by IP, change cvars, set binds, read errors. It is off by default, and until you enable it none of the other guides that say "open the console" will work. There are three ways to switch it on; any one is enough, and this covers all of them plus the reasons it sometimes refuses to stay on.</p>
10 +
11 +<h2>1. Enable it in the keyboard options</h2>
12 +<p>The menu route works without touching any files:</p>
13 +<ol>
14 +<li>From the main menu, open <strong>Options → Keyboard</strong>.</li>
15 +<li>Click <strong>Advanced</strong>.</li>
16 +<li>Tick <strong>Enable developer console (~)</strong> and confirm.</li>
17 +</ol>
18 +<p>The console now opens with the tilde key <code>~</code> (the key above Tab). This setting is stored in your config, so it persists across launches unless something overwrites the config.</p>
19 +
20 +<h2>2. Force it on with a launch option</h2>
21 +<p>The most reliable method, because it applies before the game even reads your config, is the <code>-console</code> launch option. In Steam, right-click <strong>Counter-Strike → Properties → General → Launch Options</strong> and add:</p>
22 +<pre>-console</pre>
23 +<p>Now the console is available from launch and even drops open at the main menu. This is the method to use if the menu tickbox keeps turning itself off, or if the game crashes before you can reach the menu — see <a href="/tutorials/cs16-crashes-on-startup">startup crash fixes</a>, where console access helps diagnose.</p>
24 +
25 +<h2>3. Bind a key to toggle it</h2>
26 +<p>If you dislike the tilde key or your keyboard layout puts something awkward there, bind console toggling to any key. Open the console once (via method 1 or 2), then:</p>
27 +<pre>bind "F8" "toggleconsole"</pre>
28 +<p>Put that line in your <a href="/tutorials/cs16-competitive-video-config">autoexec.cfg</a> so the bind loads every session. <code>toggleconsole</code> both opens and closes the window.</p>
29 +
30 +<h2>4. Make it stick</h2>
31 +<p>If the console keeps disabling itself, the cause is almost always a config that resets on launch. The engine rewrites <code>config.cfg</code> on exit, so an edit there can be lost. The durable combination is:</p>
32 +<ul>
33 +<li>The <code>-console</code> launch option (applies regardless of config).</li>
34 +<li>Your console-related binds in <code>autoexec.cfg</code>, which the game execs at startup and does not overwrite.</li>
35 +</ul>
36 +<p>With <code>-console</code> set you never depend on the tickbox surviving.</p>
37 +
38 +<h2>5. Use it</h2>
39 +<p>Once open, the console takes commands directly. The essentials you will reach for immediately:</p>
40 +<pre>connect 203.0.113.10:27015 // join a server by IP
41 +name "YourNick" // set your name
42 +fps_max 100 // cap FPS
43 +bind f1 "m4a1; vesthelm" // a buy bind</pre>
44 +<p>Typing any cvar with no value echoes its current setting, which is how you verify everything else you configure. From here, the direct-connect and <a href="/tutorials/cs16-buy-binds">buy-bind</a> guides become usable.</p>
45 +
46 +<h2>6. Read errors and history in the console</h2>
47 +<p>Beyond typing commands, the console is a scrolling log of what the engine is doing, and that is where problems announce themselves. When a map fails to load, a bind misfires, or content is missing, the reason is printed here — a line like <code>Cannot find wad file</code> or a failed download shows up in this window and nowhere else. Learn to scroll it back after anything goes wrong rather than guessing. You can also recall previous commands with the up-arrow, which saves retyping a long <code>connect</code> line, and copy text out of it to share an exact error message. Treat the console as your primary diagnostic tool, not just a command box; nearly every troubleshooting guide on this site ends by asking you to read something back from it.</p>
48 +
49 +<h2>Common errors</h2>
50 +<ul>
51 +<li><strong>Tilde does nothing after ticking the option</strong> — your <code>~</code> key is remapped, or a non-US layout put another character there. Bind a different key with <code>toggleconsole</code>.</li>
52 +<li><strong>Console keeps turning off between sessions</strong> — a config overwrite. Add the <code>-console</code> launch option so it does not depend on the tickbox.</li>
53 +<li><strong>Commands typed in chat do nothing</strong> — you are in the in-game chat box (T), not the console. The console is a separate overlay opened with your bound key.</li>
54 +<li><strong>No console at the main menu</strong> — you enabled it only in-game via the menu; add <code>-console</code> to have it available from launch.</li>
55 +<li><strong>Bind lost on restart</strong> — you put <code>bind ... toggleconsole</code> in <code>config.cfg</code>; move it to <code>autoexec.cfg</code>.</li>
56 +</ul>
57 +
58 +<h2>Verification</h2>
59 +<p>Press your console key at the main menu — the overlay should slide down. Type a harmless query and confirm it echoes a value:</p>
60 +<pre>fps_max</pre>
61 +<p>The console prints the current <code>fps_max</code>. If it responds, the console is live and every command-driven guide on the site is now available to you. If it opens in-game but not at the menu, add <code>-console</code> to your launch options and it will be there from the moment the game starts.</p>
+73 -0 fastdl-bzip2-compression/en.md A
@@ -0,0 +1,73 @@
1 +---
2 +title: "Compressing FastDL Files with bzip2 (and Why It Matters)"
3 +excerpt: "Halve your FastDL transfer sizes: how the CS 1.6 client requests a .bz2 first, the exact naming rule, a script to compress a whole mirror, and why you keep the originals too."
4 +category: "administration"
5 +tags: "fastdl, bzip2"
6 +image: ""
7 +read_time: "8 min read"
8 +---
9 +<p>FastDL already moves downloads off the slow game channel onto HTTP (<a href="/tutorials/fastdl-setup-guide">setup here</a>). bzip2 compression is the next win on top of that: the client fetches a compressed copy and decompresses it locally, cutting map and model transfer sizes by roughly half. For a 20 MB custom map that is the difference between a fast join and a player giving up. The mechanism is simple but has one strict naming rule that trips everyone up.</p>
10 +
11 +<h2>1. How the client uses .bz2</h2>
12 +<p>When the GoldSrc client needs a file over FastDL, it does not ask for the raw file first &mdash; it asks for the <strong>bzip2-compressed</strong> version, and only falls back to the uncompressed file if the compressed one is absent:</p>
13 +<pre>1. GET /cstrike/maps/de_rats.bsp.bz2 (tried first)
14 +2. GET /cstrike/maps/de_rats.bsp (fallback if .bz2 is missing)</pre>
15 +<p>So if you place a <code>.bz2</code> next to every large file, clients transparently download the smaller version and unpack it into their own game folder. You do nothing on the client side; the engine handles decompression.</p>
16 +
17 +<h2>2. The naming rule (the part everyone breaks)</h2>
18 +<p>The compressed filename must be the <strong>full original filename plus <code>.bz2</code></strong> &mdash; keep the original extension in the middle:</p>
19 +<table>
20 +<thead><tr><th>Original</th><th>Correct .bz2 name</th><th>Wrong</th></tr></thead>
21 +<tbody>
22 +<tr><td><code>de_rats.bsp</code></td><td><code>de_rats.bsp.bz2</code></td><td><code>de_rats.bz2</code></td></tr>
23 +<tr><td><code>v_knife.mdl</code></td><td><code>v_knife.mdl.bz2</code></td><td><code>v_knife.mdl.bz2</code> &check;</td></tr>
24 +<tr><td><code>ambience.wav</code></td><td><code>ambience.wav.bz2</code></td><td><code>ambience.bz2</code></td></tr>
25 +</tbody>
26 +</table>
27 +<p>Dropping the original extension (<code>de_rats.bz2</code>) is the classic mistake &mdash; the client requests <code>de_rats.bsp.bz2</code>, gets a 404, and silently falls back to the slow uncompressed download. The good news: <code>bzip2</code> produces exactly the right name by default.</p>
28 +
29 +<h2>3. Compress a single file</h2>
30 +<p>Use <code>bzip2 -k</code> so it <strong>keeps</strong> the original &mdash; you need both copies (see step 5):</p>
31 +<pre>cd /var/www/fastdl/cstrike/maps
32 +bzip2 -k de_rats.bsp # creates de_rats.bsp.bz2, keeps de_rats.bsp</pre>
33 +<p>Without <code>-k</code>, <code>bzip2</code> deletes the source after compressing, which breaks the fallback path and any client that asks for the raw file.</p>
34 +
35 +<h2>4. Compress a whole mirror at once</h2>
36 +<p>You will not do this by hand for hundreds of files. This script walks the mirror and compresses only the content types worth compressing, skipping anything that already has an up-to-date <code>.bz2</code>:</p>
37 +<pre>#!/bin/bash
38 +# bz2-mirror.sh -- compress a FastDL tree
39 +ROOT=/var/www/fastdl/cstrike
40 +find "$ROOT" -type f \
41 + \( -name '*.bsp' -o -name '*.mdl' -o -name '*.wav' \
42 + -o -name '*.spr' -o -name '*.tga' \) \
43 + ! -name '*.bz2' -print0 |
44 +while IFS= read -r -d '' f; do
45 + if [ ! -f "$f.bz2" ] || [ "$f" -nt "$f.bz2" ]; then
46 + bzip2 -kf "$f"
47 + echo "compressed $f"
48 + fi
49 +done</pre>
50 +<p>The <code>[ "$f" -nt "$f.bz2" ]</code> test re-compresses only files newer than their existing archive, so re-running after adding a map is cheap. Run it from cron after every content sync, or right after you copy new maps to the mirror.</p>
51 +
52 +<h2>5. Why you keep the uncompressed originals</h2>
53 +<p>It is tempting to delete the raw <code>.bsp</code> once the <code>.bz2</code> exists to save disk. Do not. Two reasons: the fallback path (some clients or edge cases still request the plain file), and the fact that your own server may serve the mirror path directly. Disk is cheap; a broken fallback is a stream of \"missing textures\" complaints. Keep both.</p>
54 +
55 +<h2>6. What not to bother compressing</h2>
56 +<p>bzip2 helps on large, compressible assets &mdash; maps, models, sounds, sprites. It does almost nothing for files that are already compressed (JPEG/PNG images, <code>.mp3</code>) and adds request overhead for tiny files. Compress the big stuff; leave already-compressed formats alone. The headline win is maps, which are large and highly compressible.</p>
57 +
58 +<h2>Common errors</h2>
59 +<ul>
60 +<li><strong>Downloads still slow despite .bz2 files</strong> &mdash; wrong name (<code>de_rats.bz2</code> instead of <code>de_rats.bsp.bz2</code>), so the client 404s and falls back. Rename to include the original extension.</li>
61 +<li><strong>Client gets missing content after you compressed</strong> &mdash; you ran <code>bzip2</code> without <code>-k</code> and deleted the originals, breaking the fallback. Regenerate the raw files.</li>
62 +<li><strong>Web server refuses .bz2</strong> &mdash; the mirror does not serve the extension as bytes. Add <code>.bz2</code> to the served types as <code>application/octet-stream</code> (see the <a href="/tutorials/fastdl-setup-guide">FastDL setup</a> nginx/apache config).</li>
63 +<li><strong>.bz2 is bigger or same size</strong> &mdash; you compressed an already-compressed file (a JPEG). Skip those formats.</li>
64 +<li><strong>New map not compressed</strong> &mdash; you added it to the <a href="/tutorials/mapcycle-txt-setup">rotation</a> and the mirror but forgot to re-run the compress script. Automate it after every sync.</li>
65 +</ul>
66 +
67 +<h2>Verification</h2>
68 +<p>Confirm the compressed file exists at the exact path the client will request, and that it is meaningfully smaller:</p>
69 +<pre>ls -la /var/www/fastdl/cstrike/maps/de_rats.bsp*
70 +# expect de_rats.bsp AND de_rats.bsp.bz2, the .bz2 roughly half the size
71 +curl -sI http://dl.example.com/cs/cstrike/maps/de_rats.bsp.bz2 | head -1
72 +# expect HTTP/1.1 200 OK</pre>
73 +<p>Then join from a client missing that map and watch it pull the <code>.bz2</code> and decompress in a second or two. If you see the raw <code>.bsp</code> being fetched instead, the compressed name or the web server type mapping is wrong.</p>
+77 -0 rcon-from-linux-cli/en.md A
@@ -0,0 +1,77 @@
1 +---
2 +title: "Sending RCON Commands from the Linux Command Line"
3 +excerpt: "How the GoldSrc RCON challenge-response protocol works over UDP, and a self-contained Python script to run rcon commands against a CS 1.6 server from a shell."
4 +category: "administration"
5 +tags: "rcon, cli"
6 +image: ""
7 +read_time: "9 min read"
8 +---
9 +<p>Being able to fire an RCON command at your CS 1.6 server from a shell — <code>changelevel</code>, <code>amx_ban</code>, a config reload — is enormously handy for scripts, cron jobs and quick fixes without launching the game. But GoldSrc RCON is not the TCP protocol that Source-era tools like <code>mcrcon</code> speak; it is a UDP challenge-response scheme, and using the wrong tool just times out. This explains the protocol and gives you a working client.</p>
10 +
11 +<h2>1. Know the protocol (why generic tools fail)</h2>
12 +<p>GoldSrc RCON runs over the same UDP game port (default 27015) and works in two steps:</p>
13 +<ol>
14 +<li>The client sends a <code>getchallenge</code> request. The server replies with a one-time challenge number.</li>
15 +<li>The client sends <code>rcon &lt;challenge&gt; "&lt;password&gt;" &lt;command&gt;</code>. The server runs it and returns the console output.</li>
16 +</ol>
17 +<p>Every packet is prefixed with four <code>0xFF</code> bytes. Because it is UDP with a challenge, TCP-based RCON tools (built for Source or Minecraft) cannot talk to it — that is the number-one reason people think "RCON is broken."</p>
18 +
19 +<h2>2. Set it up on the server</h2>
20 +<p>RCON must be enabled with a password in <a href="/tutorials/setup-server-cfg-cs16">server.cfg</a>:</p>
21 +<pre>rcon_password "USE-A-LONG-RANDOM-STRING"</pre>
22 +<p>Because RCON is brute-forceable over the network, make the password long and random, and never expose the game port to the whole internet if you can restrict it — see <a href="/tutorials/cs16-server-firewall-ports">which ports to open</a>. On ReHLDS you also get failed-attempt limits worth enabling.</p>
23 +
24 +<h2>3. A self-contained Python RCON client</h2>
25 +<p>This implements the two-step handshake with only the standard library:</p>
26 +<pre>#!/usr/bin/env python3
27 +import socket, sys
28 +
29 +def rcon(host, port, password, command):
30 + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
31 + s.settimeout(4)
32 + s.connect((host, port))
33 +
34 + # 1) get a challenge
35 + s.send(b"\xFF\xFF\xFF\xFFgetchallenge\n")
36 + reply = s.recv(1400).decode("latin-1", "ignore")
37 + # reply looks like: \xFF\xFF\xFF\xFFchallenge rcon 1234567890
38 + challenge = reply.split("rcon")[1].strip()
39 +
40 + # 2) send the command
41 + pkt = 'rcon %s "%s" %s' % (challenge, password, command)
42 + s.send(b"\xFF\xFF\xFF\xFF" + pkt.encode("latin-1") + b"\n")
43 + return s.recv(4096).decode("latin-1", "ignore")
44 +
45 +if __name__ == "__main__":
46 + host, port, pw = sys.argv[1], int(sys.argv[2]), sys.argv[3]
47 + cmd = " ".join(sys.argv[4:])
48 + print(rcon(host, port, pw, cmd).lstrip("\xFF").lstrip("l"))</pre>
49 +<p>Save it as <code>rcon.py</code>, make it executable, and call it:</p>
50 +<pre>chmod +x rcon.py
51 +./rcon.py 127.0.0.1 27015 "your-rcon-password" status
52 +./rcon.py 127.0.0.1 27015 "your-rcon-password" changelevel de_inferno</pre>
53 +<p>The reply is prefixed with <code>0xFF 0xFF 0xFF 0xFF l</code>; the script strips that so you get clean console text.</p>
54 +
55 +<h2>4. Useful things to run</h2>
56 +<pre>./rcon.py HOST 27015 PW "status" // players, map, uptime
57 +./rcon.py HOST 27015 PW "amx_map de_nuke" // change map via AMXX
58 +./rcon.py HOST 27015 PW "exec server.cfg" // reload config
59 +./rcon.py HOST 27015 PW "amx_reloadadmins" // re-read users.ini</pre>
60 +<p>Quote a command with arguments as one shell argument if it contains spaces you want kept together, e.g. <code>"say hello everyone"</code>. This is the backbone of remote admin scripting — pair it with the <a href="/tutorials/monitor-server-uptime-alerts">uptime monitor</a> to auto-<code>changelevel</code> off a stuck map, or with the <a href="/tutorials/parse-cs16-server-logs">log parser</a> to react to events.</p>
61 +
62 +<h2>5. Keep the password out of your shell history</h2>
63 +<p>A password on the command line lands in <code>~/.bash_history</code> and in <code>ps</code> output. For anything recurring, read it from an environment variable or a mode-600 file instead of typing it inline, and restrict who can run the script.</p>
64 +
65 +<h2>Troubleshooting</h2>
66 +<ul>
67 +<li><strong>Timeout / no reply</strong> — the UDP port is firewalled, the server is on a different port, or you are using a TCP RCON tool. Confirm the port answers a normal query first.</li>
68 +<li><strong><code>Bad rcon_password</code></strong> — the password is wrong or was rotated. It must match <code>rcon_password</code> exactly, including case.</li>
69 +<li><strong><code>Bad challenge</code></strong> — you reused an old challenge; each command needs a fresh <code>getchallenge</code>. The script does this every call.</li>
70 +<li><strong>Command runs but returns nothing</strong> — many commands (like <code>changelevel</code>) produce no console text; that is normal. Run <code>status</code> to confirm the channel works.</li>
71 +<li><strong>RCON locked out</strong> — on ReHLDS, repeated bad passwords trip the failure limit and temporarily block your IP. Wait it out and fix the password.</li>
72 +</ul>
73 +
74 +<h2>Verification</h2>
75 +<p>Run <code>status</code> against the server and confirm you get the player list and current map back:</p>
76 +<pre>./rcon.py 127.0.0.1 27015 "your-rcon-password" status</pre>
77 +<p>A clean <code>hostname</code>, <code>map</code> and player table means the handshake and password are correct. Then run a harmless state change like <code>exec server.cfg</code> and confirm from the game console that it took. Once the script works locally, you can safely wire it into cron and monitoring.</p>
0 78