12 KiB
megastructure.surf
A Docker-based Counter-Strike: Source surf server with Shavit BHopTimer and community physics fix plugins.
Overview
This repository contains a complete CSS surf server setup using Docker containers. The setup includes:
- CSS Dedicated Server (CSSDS) - Running on 64-bit binaries for improved performance
- Shavit BHopTimer - Actively maintained timer system (v4.0.1) with MySQL support
- MariaDB - Database backend for timer records and player data
- MetaMod:Source - Plugin loader framework
- SourceMod - Server administration and plugin platform
- Community Physics Plugins - Essential surf/bhop fixes and enhancements
Architecture
Docker Services
cssds (CSS Dedicated Server)
- Based on Debian Bookworm
- Runs SteamCMD to download/update CSS DS and TF2 DS (for 64-bit binaries)
- Installs MetaMod:Source and SourceMod
- Installs surf-specific plugins and timer system
- Uses 64-bit server binaries for better performance
- Port: 27015 (configurable via
SRCDS_PORT)
mariadb (Database)
- MariaDB 10.11 for timer data persistence
- Stores player records, map times, rankings
- Port: 3306 (internal)
- Data persisted in
./sql:/var/lib/mysql
Key Files
.
├── docker-compose.yaml # Service orchestration
├── etc/
│ ├── cssds.dockerfile # CSS DS container definition
│ ├── mariadb.dockerfile # MariaDB container definition
│ ├── run.sh # Main setup and launch script
│ ├── update_cssds.txt # SteamCMD script for CSS DS
│ ├── update_tf2ds.txt # SteamCMD script for TF2 DS (64-bit libs)
│ └── cfg/
│ └── server.cfg # Server configuration
└── sql/ # MariaDB data directory (volume mount)
Installed Plugins
Timer System
Shavit BHopTimer v4.0.1 (GitHub)
- Actively maintained (last update: February 2026)
- Full surf/bhop timer with MySQL backend
- Replays, rankings, zone system, statistics
- Better SQL schema design than archived alternatives
- Config location:
addons/sourcemod/configs/shavit/ - Configured to use JSON zones from surf-zones repository
- Zones loaded from
https://wrldspawn.github.io/surf-zones/z/{map}.json - Includes stripper configurations and mapfixes
- Matches KSF (Kreedz Surf Federation) server behavior
- Use
!setmaxvelin-game to configure max velocity per map
- Zones loaded from
Physics Fix Plugins
MomSurfFix v1.1.5 (GitHub)
- Fixes Source engine surf physics to match Momentum Mod behavior
- Essential for proper surf mechanics
PushFix Definitive Edition v1.0.0 (GitHub)
- Fixes player collision and push mechanics
- Prevents physics exploits
EventQueue Fix v1.3.2 (GitHub)
- Fixes map entity timing issues
- Ensures triggers and outputs work correctly
RNGFix v1.1.3 (GitHub)
- Fixes Source engine RNG determinism issues
- Ensures consistent physics behavior
Base Plugins
SourceMod includes built-in plugins for server administration:
- Admin Menu, Basic Commands, Player Commands
- Rock The Vote, Map Nominations, MapChooser
- Reserved Slots, Basic Bans
- And more (see
etc/run.shcomments for full list)
Setup & Usage
Prerequisites
- Docker
- Docker Compose
- ~10GB disk space for server files
Environment Variables
Configure in docker-compose.yaml:
METAMOD_VERSION: "1.11" # MetaMod:Source version
SOURCEMOD_VERSION: "1.11" # SourceMod version
SRCDS_PORT: 27015 # Server port
SRCDS_MAXPLAYERS: 32 # Max player slots
SRCDS_STARTMAP: "surf_ski_2" # Starting map
Building & Running
# Build the containers
docker-compose build
# Start the services
docker-compose up -d
# View logs
docker-compose logs -f cssds
# Stop the services
docker-compose down
First-Time Database Configuration
After the first build, configure Shavit to use MariaDB:
- Edit
addons/sourcemod/configs/databases.cfg:
"Databases"
{
"shavit"
{
"driver" "mysql"
"host" "mariadb"
"database" "shavit"
"user" "root"
"pass" "your_password"
}
}
- Shavit will automatically create tables on first connection
JSON Zones Configuration
The server is automatically configured to use JSON zones instead of SQL-based zones. This provides several advantages:
Automatic Setup:
- Zones are loaded from the community-maintained surf-zones repository
- Includes 400+ maps with pre-configured zones, stripper configs, and mapfixes
- No manual zone creation needed for supported maps
- Automatically downloads:
https://wrldspawn.github.io/surf-zones/z/{map}.json
Configuration Files Created:
cfg/sourcemod/plugin.shavit-zones.cfg- Disables SQL zones (shavit_zones_usesql "0")cfg/sourcemod/plugin.shavit-zones-json.cfg- Sets JSON URLaddons/stripper/- Map entity fixes and modificationsaddons/sourcemod/configs/shavit-mapfixes.cfg- Map-specific settingsaddons/sourcemod/configs/shavit-styles.cfg- KSF-style configurations
Benefits:
- ✅ No manual zone editing required for popular maps
- ✅ Community-maintained and regularly updated
- ✅ Includes map fixes for common issues
- ✅ Matches KSF server behavior and standards
- ✅ Faster deployment (no SQL import needed)
Important Note: The sv_maxvelocity settings in mapfixes won't auto-apply. After loading a map, use the in-game command:
!setmaxvel <value>
For most surf maps, use !setmaxvel 3500. Some maps may require different values (check surf-zones repo for specific maps).
Server Configuration
Edit etc/cfg/server.cfg for server settings:
- Hostname, rcon password
- Game settings (gravity, air accelerate, etc.)
- SourceMod configurations
Development Notes
Plugin Installation Pattern
All plugins follow an idempotent installation pattern in etc/run.sh:
if [ ! -f "$CSTRIKE/addons/sourcemod/plugins/plugin.smx" ]; then
wget "https://github.com/author/repo/releases/download/version/plugin.zip"
unzip "plugin.zip"
rm "plugin.zip"
echo "Installed Plugin vX.Y.Z"
fi
This allows safe re-runs without reinstalling existing plugins.
Version Strategy
Fixed versions are used (not dynamic latest detection) for:
- Stability - Known working versions prevent unexpected breaks
- Reproducibility - Docker builds are deterministic
- No API dependencies - Avoids GitHub API rate limits
- Easy rollback - Can revert to specific versions if issues arise
64-bit Binary Support
The server uses 64-bit binaries for improved performance:
- TF2 DS is downloaded for its 64-bit libraries
libsteam_api.soandsrcds_linux64are copied from TF2 to CSS_srv.sobinaries are symlinked to regular.sonamessteamclient.sois located and symlinked to expected paths
Run Script Flow
The etc/run.sh script executes in this order:
- update_cssds() - Download/update CSS DS via SteamCMD
- update_tf2ds() - Download/update TF2 DS for 64-bit binaries
- copy_64bit() - Copy 64-bit libraries from TF2 to CSS
- symlink_binaries() - Create symlinks for server binaries
- steamclient_binary() - Locate and symlink steamclient.so
- install_metamod() - Install MetaMod:Source if missing
- install_sourcemod() - Install SourceMod if missing
- install_surf() - Install timer and physics plugins
- configure_shavit_zones() - Download and configure JSON zones, stripper configs, and mapfixes
- cfg() - Copy server configuration
- run_cssds() - Launch the dedicated server
Verification
Check Installed Plugins
docker exec -it surf_megastructure-cssds-1 \
ls -la /home/steam/cssds/cstrike/addons/sourcemod/plugins/*.smx
Check Shavit Configuration
docker exec -it surf_megastructure-cssds-1 \
ls -la /home/steam/cssds/cstrike/addons/sourcemod/configs/shavit/
Check JSON Zones Configuration
# Check zone configuration files
docker exec -it surf_megastructure-cssds-1 \
cat /home/steam/cssds/cstrike/cfg/sourcemod/plugin.shavit-zones.cfg
# Check JSON URL configuration
docker exec -it surf_megastructure-cssds-1 \
cat /home/steam/cssds/cstrike/cfg/sourcemod/plugin.shavit-zones-json.cfg
# Check stripper configs installed
docker exec -it surf_megastructure-cssds-1 \
ls -la /home/steam/cssds/cstrike/addons/stripper/
# Check mapfixes
docker exec -it surf_megastructure-cssds-1 \
cat /home/steam/cssds/cstrike/addons/sourcemod/configs/shavit-mapfixes.cfg
In-Game Verification
Connect to the server and run:
sm plugins list
You should see:
- Shavit BHopTimer (multiple modules)
- momsurffix2
- pushfix_de
- eventqueuefix
- rngfix
- Standard SourceMod plugins
Troubleshooting
Plugins Not Loading
- Check MetaMod is loaded:
meta list - Check SourceMod is loaded:
sm version - Check plugin errors:
sm plugins listand look for "Failed" or "Error" - Check logs:
addons/sourcemod/logs/
Database Connection Issues
- Verify MariaDB container is running:
docker ps - Check database credentials in
databases.cfg - Check Shavit logs:
addons/sourcemod/logs/shavit/ - Test connection:
sm_sql_query shavit "SELECT 1"
Zones Not Loading / Map Has No Zones
Symptoms: Map loads but no start/end zones, timer doesn't work
Solutions:
-
Check if map is in surf-zones repository:
- Visit: https://github.com/wrldspawn/surf-zones/tree/main/z
- Search for your map name (e.g.,
surf_ski_2.json) - Not all maps have pre-made zones
-
Verify JSON zones are enabled:
// In console sm_cvar shavit_zones_usesql // Should show: "shavit_zones_usesql" = "0" -
Check zone loading errors:
- Check
addons/sourcemod/logs/shavit/ - Look for HTTP errors or JSON parsing failures
- Check
-
Create zones manually (if map not in repo):
// In-game !zones // Open zone editor !start // Create start zone !end // Create end zone- Zones created in-game are saved to the database (not JSON)
-
Network connectivity:
- Verify container can reach GitHub:
docker exec -it surf_megastructure-cssds-1 curl -I https://wrldspawn.github.io/ - Check firewall/proxy settings
- Verify container can reach GitHub:
Note: If a map doesn't exist in the surf-zones repository, you'll need to create zones manually using the in-game zone editor (!zones). These will be saved to your MariaDB database.
Server Won't Start
- Check logs:
docker-compose logs cssds - Verify port 27015 is available
- Check disk space for server files
- Verify SteamCMD downloaded files successfully
Future Enhancements
Potential Additions
- FastDL - Fast map download server (HTTP/Web server for map downloads)
- SourceBans - Web-based ban management system
- Map rotation - Automated map cycling configuration
- GOTV - Source TV for spectating/recording matches
- Workshop maps - Steam Workshop integration for map downloads
- Backup system - Automated database and config backups
Maintenance
- Update plugin versions periodically
- Monitor Shavit GitHub for new releases
- Check for MetaMod/SourceMod updates
- Review server logs for errors or exploits
Credits
- Shavit BHopTimer - shavitush
- MomSurfFix - GAMMACASE
- PushFix DE - GAMMACASE
- EventQueue Fix - hermansimensen
- RNGFix - jason-e
- MetaMod:Source - AlliedModders
- SourceMod - AlliedModders
License
This setup configuration is provided as-is. Individual components (Shavit, SourceMod, etc.) retain their original licenses.