added 7dtd server

This commit is contained in:
2026-09-17 09:31:31 -06:00
parent e87d7fddc7
commit ed14d9da80
5 changed files with 283 additions and 1 deletions

View File

@@ -26,6 +26,6 @@ ansible-playbook -i inventory.ini ansible-playbook.yml --skip-tags wazuh --ask-b
# Full run (no --tags) — unchanged behavior
```
Tags: `packages`, `directories`, `sysctl`, `network`, `wireguard`, `npm`, `gitea`, `jellyfin`, `wazuh`, `minecraft`, `zomboid`, `images`
Tags: `packages`, `directories`, `sysctl`, `network`, `wireguard`, `npm`, `gitea`, `jellyfin`, `wazuh`, `minecraft`, `zomboid`, `7dtd`, `images`
Note: `--tags` runs skip the bulk image pull (tagged `images`); containers auto-pull their image on deploy (`podman_container` pull policy defaults to `missing`).

View File

@@ -32,6 +32,8 @@
tags: [wazuh]
- role: minecraft
tags: [minecraft]
- role: 7dtd
tags: [7dtd]
# - role: zomboid
# tags: [zomboid]

78
roles/7dtd/tasks/main.yml Normal file
View File

@@ -0,0 +1,78 @@
---
# 7 Days to Die dedicated server (vinanrra/7dtd-server container, LinuxGSM-based, SteamCMD-installed).
# PUBLIC server: players connect to 7dtd.boxswapper.io:26900 (TCP+UDP) and enter the join password
# (sdtd_server_password). Server config is rendered from roles/7dtd/templates/sdtdserver.xml.j2 on
# every deploy - vars.yml is the source of truth for the server config.
# External prerequisites (NOT managed by this repo):
# - Cloudflare A record 7dtd.boxswapper.io -> public IP (grey-cloud, like mc.boxswapper.io)
# - Router port forwards: TCP+UDP 26900, UDP 26901-26902 + TCP 8081 (telnet) -> 10.10.0.47
# - CHANGED sdtd_server_password / sdtd_telnet_password in vars.yml before first deploy
- name: Create 7 Days to Die data directory
ansible.builtin.file:
path: /opt/apps/7dtd/data
state: directory
mode: '0755'
# The container (linuxserver-style base) runs as uid/gid 1000 (PUID/PGID) and chowns its volumes on
# start; pre-seeding with that ownership lets the init script and server write alongside our xml.
- name: Create 7 Days to Die saves dir (container user)
ansible.builtin.file:
path: /opt/apps/7dtd/data/7DaysToDie
state: directory
owner: '1000'
group: '1000'
mode: '0755'
- name: Create 7 Days to Die serverfiles directory (container user)
ansible.builtin.file:
path: /opt/apps/7dtd/serverfiles
state: directory
owner: '1000'
group: '1000'
mode: '0755'
- name: Template 7 Days to Die serverconfig from vars.yml
ansible.builtin.template:
src: sdtdserver.xml.j2
dest: /opt/apps/7dtd/serverfiles/sdtdserver.xml
owner: '1000'
group: '1000'
mode: '0644'
- name: Deploy 7 Days to Die Server
containers.podman.podman_container:
image: "{{ sdtd_image }}"
name: 7dtd
env: "{{ sdtd_env_base }}"
restart_policy: always
recreate: true
state: started
volumes:
- /opt/apps/7dtd/data:/home/sdtdserver/.local/share/7DaysToDie:z
- /opt/apps/7dtd/serverfiles:/home/sdtdserver/serverfiles:z
- /usr/share/zoneinfo/America/Denver:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
# Required: game port (TCP+UDP), Steam query/beacon ports (UDP)
- "26900:26900/tcp"
- "26900:26900/udp"
- "26901:26901/udp"
- "26902:26902/udp"
# Optional: telnet admin console (gated by sdtd_telnet_password)
- "8081:8081/tcp"
network:
- npm_internal
ip: '{{ sdtd_ip }}'
vars:
# sdtd_env_base: START_MODE=1 starts the server; PUID/PGID match the pre-seeded dir ownership;
# MONITOR=YES restarts the game process if it crashes (LinuxGSM cron).
# IMPORTANT: restart_policy: always is only valid with START_MODE=1 (never 0/2/4 per image docs).
sdtd_env_base:
START_MODE: "{{ sdtd_start_mode }}"
VERSION: "{{ sdtd_version }}"
PUID: "{{ sdtd_puid }}"
PGID: "{{ sdtd_pgid }}"
TimeZone: "{{ sdtd_timezone }}"
BACKUP: "{{ sdtd_backup }}"
MONITOR: "{{ sdtd_monitor }}"
TEST_ALERT: "NO"

View File

@@ -0,0 +1,134 @@
<?xml version="1.0"?>
<!-- Managed by Ansible (roles/7dtd/templates/sdtdserver.xml.j2) - local edits are overwritten on re-run. -->
<!-- Source of truth: sdtd_* variables in vars.yml. Applied on every deploy (template task runs each time). -->
<ServerSettings>
<!-- GENERAL SERVER SETTINGS -->
<!-- Server representation -->
<property name="ServerName" value="{{ sdtd_servername }}" />
<property name="ServerDescription" value="{{ sdtd_server_description }}" />
<property name="ServerWebsiteURL" value="{{ sdtd_website_url }}" />
<property name="ServerPassword" value="{{ sdtd_server_password }}" />
<property name="ServerLoginConfirmationText" value="" />
<property name="Region" value="{{ sdtd_region }}" />
<property name="Language" value="{{ sdtd_language }}" />
<!-- Networking -->
<property name="ServerPort" value="{{ sdtd_port }}" />
<!-- Visibility: 2 = public, 1 = shown to friends only, 0 = not listed (private, direct-connect only) -->
<property name="ServerVisibility" value="{{ sdtd_visibility }}" />
<!-- Public servers behind correct port forwards should disable SteamNetworking (no NAT relay needed) -->
<property name="ServerDisabledNetworkProtocols" value="{{ sdtd_disabled_network_protocols }}" />
<property name="ServerMaxWorldTransferSpeedKiBs" value="512" />
<!-- Slots -->
<property name="ServerMaxPlayerCount" value="{{ sdtd_max_players }}" />
<property name="ServerReservedSlots" value="0" />
<property name="ServerReservedSlotsPermission" value="100" />
<property name="ServerAdminSlots" value="0" />
<property name="ServerAdminSlotsPermission" value="0" />
<!-- Admin interfaces -->
<property name="WebDashboardEnabled" value="false" />
<property name="WebDashboardPort" value="8080" />
<property name="WebDashboardUrl" value="" />
<property name="EnableMapRendering" value="false" />
<property name="TelnetEnabled" value="{{ sdtd_telnet_enabled | lower }}" />
<property name="TelnetPort" value="8081" />
<property name="TelnetPassword" value="{{ sdtd_telnet_password }}" />
<property name="TelnetFailedLoginLimit" value="10" />
<property name="TelnetFailedLoginsBlocktime" value="10" />
<property name="TerminalWindowEnabled" value="true" />
<!-- Folder and file locations -->
<property name="AdminFileName" value="serveradmin.xml" />
<!-- Other technical settings -->
<property name="EACEnabled" value="{{ sdtd_eac_enabled | lower }}" />
<property name="HideCommandExecutionLog" value="0" />
<property name="MaxUncoveredMapChunksPerPlayer" value="131072" />
<property name="PersistentPlayerProfiles" value="false" />
<!-- GAMEPLAY -->
<!-- World. GameWorld: "RWG" for random gen (uses WorldGenSeed/WorldGenSize below) or an existing
world name ("Navezgane", "PREGEN01", ...). GameName sets the save/decoration seed name. -->
<property name="GameWorld" value="{{ sdtd_game_world }}" />
<property name="WorldGenSeed" value="{{ sdtd_worldgen_seed }}" />
<property name="WorldGenSize" value="{{ sdtd_worldgen_size }}" />
<property name="GameName" value="{{ sdtd_game_name }}" />
<property name="GameMode" value="{{ sdtd_game_mode }}" />
<!-- Difficulty: 0 = Scavenger, 1 = Adventurer, 2 = Nomad, 3 = Warrior, 4 = Survivalist, 5 = Insane -->
<property name="GameDifficulty" value="{{ sdtd_difficulty }}" />
<property name="BlockDamagePlayer" value="100" />
<property name="BlockDamageAI" value="100" />
<property name="BlockDamageAIBM" value="100" />
<property name="XPMultiplier" value="{{ sdtd_xp_multiplier }}" />
<property name="PlayerSafeZoneLevel" value="5" />
<property name="PlayerSafeZoneHours" value="5" />
<!-- Day/night: DayNightLength = real minutes per in-game day, DayLightLength = in-game hours of daylight -->
<property name="BuildCreate" value="false" />
<property name="DayNightLength" value="{{ sdtd_day_night_length }}" />
<property name="DayLightLength" value="{{ sdtd_day_light_length }}" />
<property name="DeathPenalty" value="1" />
<!-- DropOnDeath: 0 = nothing, 1 = everything, 2 = toolbelt only, 3 = backpack only, 4 = delete all -->
<property name="DropOnDeath" value="{{ sdtd_drop_on_death }}" />
<property name="DropOnQuit" value="0" />
<property name="BedrollDeadZoneSize" value="15" />
<property name="BedrollExpiryTime" value="45" />
<!-- Performance related -->
<property name="MaxSpawnedZombies" value="{{ sdtd_max_spawned_zombies }}" />
<property name="MaxSpawnedAnimals" value="50" />
<property name="ServerMaxAllowedViewDistance" value="12" />
<property name="MaxQueuedMeshLayers" value="1000" />
<!-- Zombie settings. ZombieMove: 0 = walk, 1 = jog, 2 = run, 3 = sprint, 4 = nightmare -->
<property name="EnemySpawnMode" value="true" />
<property name="EnemyDifficulty" value="0" />
<property name="ZombieFeralSense" value="0" />
<property name="ZombieMove" value="{{ sdtd_zombie_move }}" />
<property name="ZombieMoveNight" value="{{ sdtd_zombie_move_night }}" />
<property name="ZombieFeralMove" value="3" />
<property name="ZombieBMMove" value="3" />
<property name="BloodMoonFrequency" value="{{ sdtd_bloodmoon_frequency }}" />
<property name="BloodMoonRange" value="0" />
<property name="BloodMoonWarning" value="8" />
<property name="BloodMoonEnemyCount" value="{{ sdtd_bloodmoon_enemy_count }}" />
<!-- Loot -->
<property name="LootAbundance" value="{{ sdtd_loot_abundance }}" />
<property name="LootRespawnDays" value="7" />
<property name="AirDropFrequency" value="{{ sdtd_airdrop_frequency }}" />
<property name="AirDropMarker" value="true" />
<!-- Multiplayer. PlayerKillingMode: 0 = no killing, 1 = kill allies only, 2 = kill strangers only, 3 = kill everyone -->
<property name="PartySharedKillRange" value="100" />
<property name="PlayerKillingMode" value="{{ sdtd_player_killing_mode }}" />
<!-- Land claim options -->
<property name="LandClaimCount" value="3" />
<property name="LandClaimSize" value="41" />
<property name="LandClaimDeadZone" value="30" />
<property name="LandClaimExpiryTime" value="7" />
<property name="LandClaimDecayMode" value="0" />
<property name="LandClaimOnlineDurabilityModifier" value="4" />
<property name="LandClaimOfflineDurabilityModifier" value="4" />
<property name="LandClaimOfflineDelay" value="0" />
<property name="DynamicMeshEnabled" value="true" />
<property name="DynamicMeshLandClaimOnly" value="true" />
<property name="DynamicMeshLandClaimBuffer" value="3" />
<property name="DynamicMeshMaxItemCache" value="3" />
<property name="TwitchServerPermission" value="90" />
<property name="TwitchBloodMoonAllowed" value="false" />
<property name="MaxChunkAge" value="-1" />
<property name="SaveDataLimit" value="-1" />
</ServerSettings>

View File

@@ -19,6 +19,9 @@ directories:
- /opt/apps/minecraft/data
- /opt/apps/zomboid
- /opt/apps/zomboid/data
- /opt/apps/7dtd
- /opt/apps/7dtd/data
- /opt/apps/7dtd/serverfiles
## Jellyfin directories for media
@@ -37,6 +40,7 @@ images:
- docker.io/wazuh/wazuh-manager:{{ wazuh_version }}
- docker.io/itzg/minecraft-server:latest
- docker.io/danixu86/project-zomboid-dedicated-server:latest
- docker.io/vinanrra/7dtd-server:latest
wazuh_version: 4.14.1
@@ -125,3 +129,67 @@ zomboid_force_update: "false"
zomboid_memory: 8g
zomboid_preset: Apocalypse
## 7 Days to Die dedicated server (vinanrra/7dtd-server container, LinuxGSM-based)
## PUBLIC server: listed in the in-game server browser; players connect to
## 7dtd.boxswapper.io:26900 (TCP+UDP) and enter the join password (sdtd_server_password).
## Server config is rendered from roles/7dtd/templates/sdtdserver.xml.j2 on every deploy —
## vars.yml is the source of truth for the server config (edits here re-apply on re-run).
## External DNS (not managed here): Cloudflare A record 7dtd.boxswapper.io -> public IP (grey-cloud,
## same as mc.boxswapper.io / zomboid.boxswapper.io). Router MUST forward TCP+UDP 26900, UDP
## 26901-26902 (Steam query) + TCP 8081 (telnet) -> 10.10.0.47.
## VERSION=stable tracks the current public build; the container auto-installs/updates via SteamCMD
## on first start. START_MODE must stay 1 with restart_policy always (see role comment).
sdtd_host: 7dtd.boxswapper.io
sdtd_ip: 10.10.0.47
sdtd_image: docker.io/vinanrra/7dtd-server:latest
sdtd_version: stable
sdtd_start_mode: "1"
sdtd_puid: 1000
sdtd_pgid: 1000
sdtd_timezone: America/Denver
sdtd_backup: "NO"
sdtd_monitor: "YES"
## CHANGE THESE before first deploy — the server is public and both passwords gate real access:
## sdtd_server_password is the join password players must enter; if it is empty the server has NO
## join password. sdtd_telnet_password guards the 8081/tcp admin console; if empty telnet only
## listens on loopback.
sdtd_server_password: h8zvU3v7WUEgLSYG
sdtd_telnet_password: HDRSEsueredu3rf3
## Change the seed + set sdtd_game_world: RWG for a fresh random-gen world on first boot
## (Navezgane = built-in map, instant start, no generation time).
sdtd_servername: "Boxswapper 7DTD"
sdtd_server_description: "You wiill die in 7 Days, retard"
sdtd_website_url: ""
sdtd_region: NorthAmericaEast
sdtd_language: English
sdtd_visibility: "2"
## SteamNetworking disabled = direct connect via forwarded ports (correct setup for this box);
## leave empty ("" ) to allow the Steam relay fallback if port forwards break.
sdtd_disabled_network_protocols: SteamNetworking
sdtd_port: 26900
sdtd_max_players: 8
sdtd_game_mode: GameModeSurvival
sdtd_game_world: Navezgane
sdtd_worldgen_seed: boxswapper
sdtd_worldgen_size: 8192
sdtd_game_name: Boxswapper
## Difficulty: 0 = Scavenger, 1 = Adventurer, 2 = Nomad, 3 = Warrior, 4 = Survivalist, 5 = Insane
sdtd_difficulty: "2"
sdtd_day_night_length: 60
sdtd_day_light_length: 18
## DropOnDeath: 0 = nothing, 1 = everything, 2 = toolbelt only, 3 = backpack only, 4 = delete all
sdtd_drop_on_death: "1"
## ZombieMove: 0 = walk, 1 = jog, 2 = run, 3 = sprint, 4 = nightmare
sdtd_zombie_move: "0"
sdtd_zombie_move_night: "3"
sdtd_bloodmoon_frequency: 7
sdtd_bloodmoon_enemy_count: 8
sdtd_loot_abundance: 100
sdtd_airdrop_frequency: 72
## PlayerKillingMode: 0 = no killing, 1 = kill allies only, 2 = kill strangers only, 3 = kill everyone
sdtd_player_killing_mode: "3"
sdtd_max_spawned_zombies: 64
sdtd_eac_enabled: "true"
sdtd_xp_multiplier: 100
sdtd_telnet_enabled: "true"