|
| 1 | +--- |
| 2 | +sidebar_position: 4 |
| 3 | +title: ColdStarter System |
| 4 | +description: Understand how Druid's ColdStarter system enables wake-on-demand automation and 70-90% cost savings |
| 5 | +--- |
| 6 | + |
| 7 | +# ColdStarter System |
| 8 | + |
| 9 | +ColdStarter is Druid's intelligent wake-on-demand system that automatically starts your game server when players connect, while keeping costs near zero when idle. It's the core technology that makes Druid cost-effective for hobby servers. |
| 10 | + |
| 11 | +## What is ColdStarter? |
| 12 | + |
| 13 | +ColdStarter acts as a lightweight listener proxy that intercepts incoming connections to your game server. When a player tries to connect: |
| 14 | + |
| 15 | +1. **Sleeping**: Server is powered down, consuming minimal resources (~0 cost) |
| 16 | +2. **Wake signal**: Player connects, ColdStarter intercepts the connection |
| 17 | +3. **Starting**: ColdStarter wakes the server in the background |
| 18 | +4. **Ready**: Player is connected to the now-running server |
| 19 | + |
| 20 | +The magic? **Your server still appears "online" in server browsers even when sleeping.** |
| 21 | + |
| 22 | +## Key Benefits |
| 23 | + |
| 24 | +### 💰 **70-90% Cost Savings** |
| 25 | + |
| 26 | +Pay only for active playtime, not idle time. A typical hobby server might run: |
| 27 | +- **Traditional hosting**: 24/7 = 720 hours/month |
| 28 | +- **With ColdStarter**: 50-150 hours/month actual playtime |
| 29 | + |
| 30 | +**Example cost breakdown:** |
| 31 | +``` |
| 32 | +Traditional: $10/month × 720 hours = $10 |
| 33 | +Druid: $0.014/hour × 100 hours = $1.40/month |
| 34 | +
|
| 35 | +Savings: 86% |
| 36 | +``` |
| 37 | + |
| 38 | +### ⚡ **Seamless User Experience** |
| 39 | + |
| 40 | +- Server shows as "online" in Minecraft/Rust/etc. server browsers |
| 41 | +- Players connect normally (10-30 second wake time) |
| 42 | +- Status messages show "Starting..." or "Waking up..." |
| 43 | +- No configuration needed by players |
| 44 | + |
| 45 | +### 🌍 **Always Available** |
| 46 | + |
| 47 | +Your server is accessible 24/7, but only costs money when actually in use. Perfect for: |
| 48 | +- Hobby servers with irregular play schedules |
| 49 | +- Friend groups in different time zones |
| 50 | +- Testing and development environments |
| 51 | +- Event-based servers |
| 52 | + |
| 53 | +## How It Works |
| 54 | + |
| 55 | +### Architecture |
| 56 | + |
| 57 | +``` |
| 58 | +Player → ColdStarter Listener → [Wake] → Game Server |
| 59 | + ↓ |
| 60 | + Lua Packet Handler |
| 61 | + (Server status response) |
| 62 | +``` |
| 63 | + |
| 64 | +### 1. Listener Proxy |
| 65 | + |
| 66 | +When your server goes idle (no players for X minutes): |
| 67 | +- Main game server shuts down |
| 68 | +- Lightweight ColdStarter listener starts on the same port |
| 69 | +- Memory footprint: ~10-50MB (vs 2-8GB for game server) |
| 70 | + |
| 71 | +### 2. Packet Handler |
| 72 | + |
| 73 | +ColdStarter uses **Lua packet handlers** to understand game-specific connection protocols: |
| 74 | + |
| 75 | +```lua |
| 76 | +-- Example: Minecraft status packet handler |
| 77 | +function handle(ctx, data) |
| 78 | + if isStatusRequest(data) then |
| 79 | + -- Send fake "server online" response |
| 80 | + sendData(generateStatusResponse({ |
| 81 | + version = "§2▶ Starting...", |
| 82 | + players = { online = 0, max = 20 }, |
| 83 | + description = "Waking up... 30s" |
| 84 | + })) |
| 85 | + elseif isLoginAttempt(data) then |
| 86 | + -- Trigger server wake |
| 87 | + finish() |
| 88 | + end |
| 89 | +end |
| 90 | +``` |
| 91 | + |
| 92 | +Each game has a custom packet handler: |
| 93 | +- **Minecraft**: Responds to status + login packets |
| 94 | +- **Rust**: Responds to query protocol |
| 95 | +- **Source games**: Responds to A2S_INFO queries |
| 96 | +- **Hytale**: Protocol TBD (ready for launch) |
| 97 | + |
| 98 | +### 3. Wake Process |
| 99 | + |
| 100 | +When a player attempts to connect: |
| 101 | + |
| 102 | +1. **Intercept**: ColdStarter receives connection |
| 103 | +2. **Respond**: Send "Starting..." status to player |
| 104 | +3. **Wake**: Restore server container from snapshot |
| 105 | +4. **Handoff**: Transfer connection to real server |
| 106 | +5. **Cleanup**: ColdStarter listener shuts down |
| 107 | + |
| 108 | +Typical wake time: **10-30 seconds** (varies by game/world size) |
| 109 | + |
| 110 | +### 4. Server Browser Integration |
| 111 | + |
| 112 | +The clever part: **Server browsers never know the server is asleep.** |
| 113 | + |
| 114 | +- **Minecraft**: Shows in server list with "🕐 Waiting..." status |
| 115 | +- **Rust**: Appears in Rust+ app and server browser |
| 116 | +- **Steam games**: Shows in Steam server browser |
| 117 | +- **Direct connect**: Works normally with IP:PORT |
| 118 | + |
| 119 | +## Supported Games |
| 120 | + |
| 121 | +ColdStarter has optimized handlers for: |
| 122 | + |
| 123 | +| Game | Status | Protocol Handler | |
| 124 | +|------|--------|------------------| |
| 125 | +| Minecraft (all variants) | ✅ Stable | `minecraft.lua` | |
| 126 | +| Rust | ✅ Stable | `rust.lua` | |
| 127 | +| Hytale | ✅ Ready | `hytale.lua` | |
| 128 | +| ARK: Survival | ✅ Stable | LGSM generic | |
| 129 | +| Palworld | ✅ Stable | LGSM generic | |
| 130 | +| Valheim | ✅ Stable | LGSM generic | |
| 131 | +| 7 Days to Die | ✅ Stable | LGSM generic | |
| 132 | +| Other LGSM games | ✅ Stable | Generic handler | |
| 133 | + |
| 134 | +**Total**: 95 published scrolls with ColdStarter support |
| 135 | + |
| 136 | +## Configuration |
| 137 | + |
| 138 | +ColdStarter is configured automatically per-scroll. Key settings: |
| 139 | + |
| 140 | +### Scroll Configuration |
| 141 | + |
| 142 | +```yaml |
| 143 | +# scroll.yaml |
| 144 | +ports: |
| 145 | + - name: game |
| 146 | + port: 25565 |
| 147 | + protocol: tcp |
| 148 | + sleep_handler: "minecraft.lua" # Packet handler |
| 149 | + check_activity: true # Monitor for idle |
| 150 | + |
| 151 | +coldstarter: |
| 152 | + idle_timeout: 300 # Shutdown after 5min idle |
| 153 | + wake_timeout: 60 # Max wake time |
| 154 | + snapshot_mode: "auto" # Enable snapshots |
| 155 | +``` |
| 156 | +
|
| 157 | +### Advanced Options |
| 158 | +
|
| 159 | +- **idle_timeout**: How long to wait before sleeping (seconds) |
| 160 | +- **wake_timeout**: Max time allowed for wake (kills if exceeded) |
| 161 | +- **snapshot_mode**: `auto` | `manual` | `none` |
| 162 | +- **custom_handler**: Path to custom Lua packet handler |
| 163 | + |
| 164 | +## Cost Optimization Tips |
| 165 | + |
| 166 | +### 1. Enable Snapshots |
| 167 | + |
| 168 | +Faster wake times = better player experience: |
| 169 | +```yaml |
| 170 | +coldstarter: |
| 171 | + snapshot_mode: "auto" |
| 172 | + snapshot_schedule: "0 4 * * *" # Daily at 4 AM |
| 173 | +``` |
| 174 | + |
| 175 | +### 2. Tune Idle Timeout |
| 176 | + |
| 177 | +Balance responsiveness vs cost: |
| 178 | +- **5 minutes**: Best for active servers (minimal downtime) |
| 179 | +- **15 minutes**: Good default for most hobby servers |
| 180 | +- **30 minutes**: Maximum savings for rarely-used servers |
| 181 | + |
| 182 | +### 3. Monitor Usage |
| 183 | + |
| 184 | +Check your actual playtime: |
| 185 | +```bash |
| 186 | +druid metrics |
| 187 | +# Shows: active hours, sleep hours, cost breakdown |
| 188 | +``` |
| 189 | + |
| 190 | +## Technical Details |
| 191 | + |
| 192 | +### Packet Handler API |
| 193 | + |
| 194 | +Lua handlers have access to: |
| 195 | + |
| 196 | +```lua |
| 197 | +-- Send data back to client |
| 198 | +sendData(string) |
| 199 | +
|
| 200 | +-- Close connection |
| 201 | +close(data) |
| 202 | +
|
| 203 | +-- Trigger server wake + handoff |
| 204 | +finish() |
| 205 | +
|
| 206 | +-- Get queue status (install/restore) |
| 207 | +get_queue() |
| 208 | +
|
| 209 | +-- Get snapshot progress |
| 210 | +get_snapshot_mode() |
| 211 | +get_snapshot_percentage() |
| 212 | +
|
| 213 | +-- Time since wake started |
| 214 | +get_finish_sec() |
| 215 | +
|
| 216 | +-- Debug logging |
| 217 | +debug_print(string) |
| 218 | +``` |
| 219 | + |
| 220 | +### Custom Handlers |
| 221 | + |
| 222 | +Create your own for unsupported games: |
| 223 | + |
| 224 | +```lua |
| 225 | +-- custom_game.lua |
| 226 | +function handle(ctx, data) |
| 227 | + -- 1. Parse incoming packet |
| 228 | + local packet_type = parsePacket(data) |
| 229 | + |
| 230 | + -- 2. Handle status requests |
| 231 | + if packet_type == "STATUS" then |
| 232 | + sendData(buildStatusResponse({ |
| 233 | + name = "My Server", |
| 234 | + players = 0, |
| 235 | + max_players = 20, |
| 236 | + status = "Waking up..." |
| 237 | + })) |
| 238 | + end |
| 239 | + |
| 240 | + -- 3. Handle connection attempts |
| 241 | + if packet_type == "CONNECT" then |
| 242 | + sendData("Please wait, server starting...") |
| 243 | + finish() -- Wake the server |
| 244 | + end |
| 245 | +end |
| 246 | +``` |
| 247 | + |
| 248 | +Place in `scrolls/<game>/packet_handler/custom_game.lua` |
| 249 | + |
| 250 | +## Performance |
| 251 | + |
| 252 | +### Resource Usage |
| 253 | + |
| 254 | +| State | CPU | RAM | Cost/hour | |
| 255 | +|-------|-----|-----|-----------| |
| 256 | +| **Active** (playing) | 100% | 2-8GB | $0.014 | |
| 257 | +| **Sleeping** (ColdStarter) | <1% | 10-50MB | ~$0 | |
| 258 | +| **Waking** (starting up) | 50-100% | 2-8GB | $0.014 | |
| 259 | + |
| 260 | +### Wake Times |
| 261 | + |
| 262 | +| Game | Cold Start | With Snapshot | |
| 263 | +|------|-----------|---------------| |
| 264 | +| Minecraft (small world) | 30-45s | 10-15s | |
| 265 | +| Minecraft (large world) | 60-90s | 20-30s | |
| 266 | +| Rust | 40-60s | 15-25s | |
| 267 | +| Palworld | 30-50s | 10-20s | |
| 268 | +| ARK | 60-120s | 20-40s | |
| 269 | + |
| 270 | +## Troubleshooting |
| 271 | + |
| 272 | +### Server Won't Wake |
| 273 | + |
| 274 | +**Symptoms**: Players connect but server stays asleep |
| 275 | + |
| 276 | +**Solutions**: |
| 277 | +1. Check packet handler logs: `druid logs coldstarter` |
| 278 | +2. Verify port configuration matches game protocol |
| 279 | +3. Test with direct connect (bypass DNS/proxy) |
| 280 | +4. Check firewall rules allow incoming traffic |
| 281 | + |
| 282 | +### Slow Wake Times |
| 283 | + |
| 284 | +**Symptoms**: Takes >60s to start |
| 285 | + |
| 286 | +**Solutions**: |
| 287 | +1. Enable snapshots for faster restore |
| 288 | +2. Reduce world/mod size |
| 289 | +3. Check available CPU/RAM resources |
| 290 | +4. Consider pre-warming (disable auto-sleep during peak hours) |
| 291 | + |
| 292 | +### "Server Offline" in Browser |
| 293 | + |
| 294 | +**Symptoms**: Server doesn't appear when sleeping |
| 295 | + |
| 296 | +**Solutions**: |
| 297 | +1. Verify `sleep_handler` is set in scroll.yaml |
| 298 | +2. Check ColdStarter process is running |
| 299 | +3. Test packet handler directly |
| 300 | +4. Review game-specific protocol requirements |
| 301 | + |
| 302 | +## FAQ |
| 303 | + |
| 304 | +**Q: Can players still see my server when it's asleep?** |
| 305 | +A: Yes! ColdStarter responds to status queries, so your server appears "online" with a "Starting..." message. |
| 306 | + |
| 307 | +**Q: What happens if multiple players connect at once?** |
| 308 | +A: ColdStarter queues all connections and wakes the server once. All players connect when ready. |
| 309 | + |
| 310 | +**Q: Does this work with mods/plugins?** |
| 311 | +A: Yes, ColdStarter is transparent to the game server. Mods/plugins work normally. |
| 312 | + |
| 313 | +**Q: Can I disable ColdStarter?** |
| 314 | +A: Yes, set `coldstarter.enabled: false` in scroll.yaml or keep the server always-on. |
| 315 | + |
| 316 | +**Q: How much does it cost when sleeping?** |
| 317 | +A: Nearly zero (~$0.001/hour for the listener process). The container is fully stopped. |
| 318 | + |
| 319 | +## |
0 commit comments