mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 05:34:43 +02:00
feat(ansible): serveur dédié Satisfactory sur gpu-01 (#74)
* feat(ansible): serveur dédié Satisfactory sur gpu-01 - Nouveau rôle satisfactory_server : install steamcmd (login anonyme, app 1690800), service systemd avec update auto en ExecStartPre, MemoryMax=16G + Nice=5 (protège le llama-server), firewalld 7777 tcp+udp - Retries steamcmd (« Missing configuration » rc=8 au premier run) - Fcontext SELinux bin_t sur steamcmd/ et server/ (203/EXEC sinon) - gateway : DNAT 192.168.1.200:7777 → gpu-01:7777 (TCP+UDP) + forward - Doc admin/ops/satisfactory.md (accès, exploitation, pièges rencontrés) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(satisfactory): ouvrir le port 8888/tcp Reliable Messaging Depuis la 1.1, le client ouvre un socket TCP :8888 en plus du jeu UDP :7777. Bloqué par firewalld, le join réussissait puis le client était déconnecté (~60 s) avec « connection to the host has been lost » (log client : LogReliableMessaging: Failed to connect to server socket). - firewalld gpu-01 : + 8888/tcp (variable satisfactory_reliable_port) - gateway s01 : DNAT + forward étendus à 8888/tcp - doc : tableau des 3 sockets + piège n°3 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(satisfactory): accès internet via IPv4 full-stack Free Le remap de port Freebox (17777→7777) ne fonctionne pas : le serveur annonce ses ports dans le protocole (externe = interne obligatoire). Option IPv4 full-stack activée → redirections 1:1 7777 tcp+udp + 8888 tcp vers funk-s01, DNAT existant inchangé. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
aaa982f93c
commit
507f4822f0
9 changed files with 290 additions and 1 deletions
|
|
@ -8,3 +8,4 @@
|
|||
- { role: nfs_client, tags: [nfs_client] }
|
||||
- { role: llama_server, tags: [llama_server] }
|
||||
- { role: node_exporter, tags: [node_exporter] }
|
||||
- { role: satisfactory_server, tags: [satisfactory_server] }
|
||||
|
|
|
|||
|
|
@ -67,6 +67,12 @@ table inet filter {
|
|||
|
||||
# Réponses WAN → cluster (connexions initiées depuis le cluster)
|
||||
iif {{ wan_interface }} oif {{ lan_interface }} ct state established,related accept
|
||||
|
||||
# Satisfactory — trafic DNATé (192.168.1.200) → gpu-01, quelle que soit la source
|
||||
# (couvre un éventuel port-forward internet depuis la box).
|
||||
# 7777 = jeu/API ; 8888 = reliable messaging TCP (1.1) — bloqué = kick à ~60 s
|
||||
ip daddr 192.168.10.20 tcp dport { 7777, 8888 } ct state new,established,related accept
|
||||
ip daddr 192.168.10.20 udp dport 7777 ct state new,established,related accept
|
||||
}
|
||||
|
||||
chain output {
|
||||
|
|
@ -77,6 +83,11 @@ table inet filter {
|
|||
table ip nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority -100;
|
||||
|
||||
# Satisfactory — DNAT WAN → serveur dédié sur gpu-01
|
||||
# (joignable via 192.168.1.200 sans route vers 192.168.10.0/24)
|
||||
iif {{ wan_interface }} tcp dport { 7777, 8888 } dnat to 192.168.10.20
|
||||
iif {{ wan_interface }} udp dport 7777 dnat to 192.168.10.20:7777
|
||||
}
|
||||
|
||||
chain postrouting {
|
||||
|
|
|
|||
35
ansible/roles/satisfactory_server/README.md
Normal file
35
ansible/roles/satisfactory_server/README.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# satisfactory_server
|
||||
|
||||
Serveur dédié **Satisfactory** sur gpu-01 — installé via **steamcmd** (login anonyme, app
|
||||
Steam `1690800`), lancé par systemd (`satisfactory-server.service`).
|
||||
|
||||
## Variables (defaults)
|
||||
|
||||
| Variable | Défaut | Rôle |
|
||||
|---|---|---|
|
||||
| `satisfactory_user` | `satisfactory` | Utilisateur système du service |
|
||||
| `satisfactory_home` | `/srv/satisfactory` | Home + racine d'install |
|
||||
| `satisfactory_install_dir` | `/srv/satisfactory/server` | Fichiers du jeu (~10 Go) |
|
||||
| `satisfactory_port` | `7777` | Jeu (UDP) + API HTTPS (TCP) |
|
||||
| `satisfactory_reliable_port` | `8888` | Reliable Messaging (TCP, ≥ 1.1) — **bloqué = kick à ~60 s** |
|
||||
| `satisfactory_update_on_start` | `true` | `steamcmd +app_update` en `ExecStartPre` à chaque (re)start |
|
||||
| `satisfactory_memory_max` | `16G` | `MemoryMax` systemd — protège llama-server (32 Go partagés) |
|
||||
| `satisfactory_nice` | `5` | Priorité CPU réduite vs llama-server |
|
||||
|
||||
## Caveats
|
||||
|
||||
- **Premier run long** : le task d'installation télécharge ~10 Go depuis Steam
|
||||
(guardé par `creates:` — ne rejoue jamais). Prévoir 10-30 min selon le débit.
|
||||
- **Mises à jour du jeu** : gérées par l'`ExecStartPre` du service (à chaque restart),
|
||||
pas par Ansible. `systemctl restart satisfactory-server` = update + relance.
|
||||
- **Sauvegardes** : `~satisfactory/.config/Epic/FactoryGame/Saved/SaveGames/server/`
|
||||
— **non sauvegardées ailleurs** (pas de backup automatisé, gap connu).
|
||||
- **Config serveur** (nom, mot de passe admin) : se fait **en jeu** à la première
|
||||
connexion (menu Server Manager), pas par fichier.
|
||||
- **RAM** : usine late-game > 12 Go possible. `MemoryMax=16G` fait tuer le jeu par
|
||||
l'OOM-killer plutôt que d'affamer le slot LLM (:1234) — augmenter si besoin via host_vars.
|
||||
- **Réseau** : ton PC (192.168.1.x) joint gpu-01:7777 via storage-01 — la chaîne
|
||||
`forward` du rôle `gateway` autorise déjà tout le trafic LAN domestique → LAN cluster.
|
||||
Dans le jeu : ajouter le serveur avec l'adresse `192.168.10.20:7777`.
|
||||
- Les ports firewalld `7778/udp` et `27015/udp` présents sur gpu-01 sont des restes
|
||||
des anciens ports « Experimental » (avant la 1.0) — inutiles désormais.
|
||||
16
ansible/roles/satisfactory_server/defaults/main.yml
Normal file
16
ansible/roles/satisfactory_server/defaults/main.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
satisfactory_user: satisfactory
|
||||
satisfactory_home: /srv/satisfactory
|
||||
satisfactory_steamcmd_dir: "{{ satisfactory_home }}/steamcmd"
|
||||
satisfactory_install_dir: "{{ satisfactory_home }}/server"
|
||||
satisfactory_app_id: 1690800 # Satisfactory Dedicated Server (Steam, login anonyme)
|
||||
satisfactory_port: 7777 # jeu (UDP) + API HTTPS (TCP)
|
||||
satisfactory_reliable_port: 8888 # socket TCP « Reliable Messaging » (depuis la 1.1) —
|
||||
# bloqué = déconnexion ~60 s après chaque join
|
||||
satisfactory_update_on_start: true # steamcmd +app_update à chaque (re)démarrage du service
|
||||
|
||||
# Garde-fous ressources : gpu-01 partage ses 32 Go avec llama-server (~10 Go résidents).
|
||||
# Une usine late-game peut dépasser 12 Go — MemoryMax fait tuer le jeu par l'OOM-killer
|
||||
# plutôt que d'affamer le slot LLM. Nice > 0 : priorité CPU au llama-server.
|
||||
satisfactory_memory_max: 16G
|
||||
satisfactory_nice: 5
|
||||
9
ansible/roles/satisfactory_server/handlers/main.yml
Normal file
9
ansible/roles/satisfactory_server/handlers/main.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
- name: Reload systemd
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
||||
- name: Restart satisfactory-server
|
||||
ansible.builtin.systemd:
|
||||
name: satisfactory-server
|
||||
state: restarted
|
||||
123
ansible/roles/satisfactory_server/tasks/main.yml
Normal file
123
ansible/roles/satisfactory_server/tasks/main.yml
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
---
|
||||
# --- Dépendances steamcmd (binaire 32 bits) ---
|
||||
|
||||
- name: Install steamcmd 32-bit dependencies
|
||||
ansible.builtin.dnf:
|
||||
name:
|
||||
- glibc.i686
|
||||
- libstdc++.i686
|
||||
- policycoreutils-python-utils # semanage (contexte SELinux, cf. plus bas)
|
||||
state: present
|
||||
|
||||
# --- Utilisateur système ---
|
||||
|
||||
- name: Create satisfactory system user
|
||||
ansible.builtin.user:
|
||||
name: "{{ satisfactory_user }}"
|
||||
system: true
|
||||
shell: /sbin/nologin
|
||||
home: "{{ satisfactory_home }}"
|
||||
create_home: true
|
||||
state: present
|
||||
|
||||
- name: Create install directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ satisfactory_user }}"
|
||||
group: "{{ satisfactory_user }}"
|
||||
mode: '0750'
|
||||
loop:
|
||||
- "{{ satisfactory_steamcmd_dir }}"
|
||||
- "{{ satisfactory_install_dir }}"
|
||||
|
||||
# --- steamcmd ---
|
||||
|
||||
- name: Download steamcmd
|
||||
ansible.builtin.get_url:
|
||||
url: "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz"
|
||||
dest: /tmp/steamcmd_linux.tar.gz
|
||||
mode: '0644'
|
||||
|
||||
- name: Extract steamcmd
|
||||
ansible.builtin.unarchive:
|
||||
src: /tmp/steamcmd_linux.tar.gz
|
||||
dest: "{{ satisfactory_steamcmd_dir }}"
|
||||
remote_src: true
|
||||
owner: "{{ satisfactory_user }}"
|
||||
group: "{{ satisfactory_user }}"
|
||||
creates: "{{ satisfactory_steamcmd_dir }}/steamcmd.sh"
|
||||
|
||||
# --- Installation initiale du jeu (~10 Go — long au premier run) ---
|
||||
# Les mises à jour suivantes passent par l'ExecStartPre du service
|
||||
# (satisfactory_update_on_start), pas par ce task.
|
||||
|
||||
# Retries : au tout premier run, steamcmd échoue souvent avec « Missing configuration »
|
||||
# (rc=8) — l'app info n'est pas encore en cache. Le run suivant passe.
|
||||
- name: Install Satisfactory dedicated server via steamcmd (first run only)
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
{{ satisfactory_steamcmd_dir }}/steamcmd.sh
|
||||
+force_install_dir {{ satisfactory_install_dir }}
|
||||
+login anonymous
|
||||
+app_update {{ satisfactory_app_id }} validate
|
||||
+quit
|
||||
creates: "{{ satisfactory_install_dir }}/FactoryServer.sh"
|
||||
become: true
|
||||
become_user: "{{ satisfactory_user }}"
|
||||
environment:
|
||||
HOME: "{{ satisfactory_home }}"
|
||||
register: satisfactory_steamcmd_install
|
||||
retries: 3
|
||||
delay: 10
|
||||
until: satisfactory_steamcmd_install.rc | default(0) == 0
|
||||
|
||||
# --- SELinux ---
|
||||
# L'unarchive depuis /tmp laisse steamcmd.sh en user_tmp_t et le jeu hérite de var_t
|
||||
# (/srv) : systemd (init_t) refuse d'exécuter ces types → 203/EXEC Permission denied.
|
||||
# bin_t sur les deux arborescences exécutables règle le problème.
|
||||
|
||||
- name: Set bin_t SELinux context on executable trees
|
||||
community.general.sefcontext:
|
||||
target: "{{ satisfactory_home }}/(steamcmd|server)(/.*)?"
|
||||
setype: bin_t
|
||||
state: present
|
||||
when: ansible_selinux.status | default('disabled') == 'enabled'
|
||||
|
||||
- name: Apply SELinux contexts
|
||||
ansible.builtin.command:
|
||||
cmd: restorecon -R {{ satisfactory_home }}
|
||||
changed_when: false
|
||||
when: ansible_selinux.status | default('disabled') == 'enabled'
|
||||
|
||||
# --- Service systemd ---
|
||||
|
||||
- name: Install satisfactory-server systemd unit
|
||||
ansible.builtin.template:
|
||||
src: satisfactory-server.service.j2
|
||||
dest: /etc/systemd/system/satisfactory-server.service
|
||||
mode: '0644'
|
||||
notify:
|
||||
- Reload systemd
|
||||
- Restart satisfactory-server
|
||||
|
||||
- name: Enable satisfactory-server service
|
||||
ansible.builtin.systemd:
|
||||
name: satisfactory-server
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
state: started
|
||||
|
||||
# --- Firewall ---
|
||||
# 7777 : jeu (UDP) + API HTTPS (TCP). 8888 : reliable messaging (TCP, depuis la 1.1).
|
||||
|
||||
- name: Open game ports in firewall
|
||||
ansible.posix.firewalld:
|
||||
port: "{{ item }}"
|
||||
permanent: true
|
||||
state: enabled
|
||||
immediate: true
|
||||
loop:
|
||||
- "{{ satisfactory_port }}/tcp"
|
||||
- "{{ satisfactory_port }}/udp"
|
||||
- "{{ satisfactory_reliable_port }}/tcp"
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
[Unit]
|
||||
Description=Satisfactory dedicated server (steamcmd, app {{ satisfactory_app_id }})
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User={{ satisfactory_user }}
|
||||
WorkingDirectory={{ satisfactory_install_dir }}
|
||||
{% if satisfactory_update_on_start %}
|
||||
# Mise à jour du jeu avant chaque démarrage (login anonyme) — ajoute ~1 min au boot.
|
||||
# Désactivable via satisfactory_update_on_start: false (host_vars).
|
||||
ExecStartPre={{ satisfactory_steamcmd_dir }}/steamcmd.sh +force_install_dir {{ satisfactory_install_dir }} +login anonymous +app_update {{ satisfactory_app_id }} +quit
|
||||
{% endif %}
|
||||
ExecStart={{ satisfactory_install_dir }}/FactoryServer.sh -Port={{ satisfactory_port }} -unattended
|
||||
Restart=on-failure
|
||||
RestartSec=15
|
||||
Nice={{ satisfactory_nice }}
|
||||
MemoryMax={{ satisfactory_memory_max }}
|
||||
TimeoutStartSec=600
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Loading…
Add table
Add a link
Reference in a new issue