Instalar un servidor de juego con SteamCMD
SteamCMD es la base común de casi todos los servidores de juego de Steam. Esta guía muestra la instalación, el login anónimo, app_update con validate, el funcionamiento como servicio systemd y los fallos típicos.
Si gestionas un servidor de juego en tu propio servidor root, casi siempre acabas con la misma herramienta: SteamCMD. Da igual si se trata de Valheim, Rust, Counter-Strike 2, Palworld, Enshrouded o ARK: los archivos del servidor están alojados en Valve y se descargan mediante el mismo cliente de línea de comandos. Una vez que tienes SteamCMD bien montado, cada juego adicional se instala cambiando un número.
Esta guía cubre justo los puntos en los que los tutoriales más cortos se detienen: las bibliotecas de 32 bits en sistemas de 64 bits, las diferencias entre Debian, Ubuntu y la familia Red Hat, los mensajes de error literales, un procedimiento de actualización que no reinicia el servidor en cada ejecución de cron, y el funcionamiento como servicio systemd.
Lo que SteamCMD es y lo que no es
SteamCMD es el Steam Console Client, una versión reducida del cliente de Steam para la línea de comandos, sin interfaz gráfica. Hace bien exactamente una cosa: descargar aplicaciones de la red de Steam, actualizarlas y verificar sus archivos. No arranca ningún servidor, no configura nada y no conoce la lógica del juego. Tras la descarga, los archivos del servidor quedan en un directorio y a partir de ahí el turno es del juego en cuestión.
Un detalle importante para entender todo el asunto de las bibliotecas: el bootstrapper de SteamCMD sigue siendo hoy un programa de 32 bits. En un sistema puramente de 64 bits le faltan las bibliotecas de tiempo de ejecución adecuadas, y ahí es justo donde falla el primer arranque para la mayoría de la gente. Los archivos del servidor descargados, en cambio, son casi siempre de 64 bits en los juegos modernos.
Preparación: un usuario propio en lugar de root
Los procesos de un servidor de juego nunca se ejecutan como root. Aceptan conexiones desde internet, en muchos títulos descargan mods del Steam Workshop y ejecutan código ajeno. Un usuario propio y sin privilegios cuesta tres comandos y limita el daño.
useradd -m -d /home/steam -s /bin/bash steam
mkdir -p /home/steam/steamcmd
chown -R steam:steam /home/steam/steamcmd
SteamCMD avisa expresamente de ello cuando se arranca como root. Si ignoras el aviso, el problema vuelve más adelante: en cuanto un directorio pertenece a root, la ejecución posterior como steam falla con un error de escritura, y el mensaje no apunta a la causa real.
Todos los comandos siguientes de este artículo se introducen como root y cambian al usuario del servicio mediante runuser -u steam --. En sistemas con sudo funciona igual de bien sudo -u steam. Si antes quieres ocuparte de la protección básica, encontrarás los fundamentos en Configurar un servidor root nuevo y Proteger SSH.
Las bibliotecas de 32 bits, distintas según el sistema
Aquí es donde las distribuciones se separan, y las listas de comandos genéricas que circulan por la red se equivocan con frecuencia en este punto.
Debian 12, Debian 13, Ubuntu 22.04 y Ubuntu 24.04
En los cuatro sistemas basta con el paquete lib32gcc-s1 del archivo principal. Es un paquete amd64 que trae consigo el runtime de 32 bits, y no necesita ninguna arquitectura i386 adicional:
apt update
apt install -y ca-certificates curl tar file lib32gcc-s1 lib32stdc++6
lib32stdc++6 no siempre hace falta para SteamCMD en sí, pero bastantes binarios de servidor más antiguos (todo lo basado en el motor Source, los títulos HLDS, algunos servidores de Unity) lo exigen. Instalarlo desde el principio ahorra una búsqueda de errores posterior. file no viene en ninguna de las imágenes mínimas y se necesita más abajo para el diagnóstico, por eso figura ya en la lista.
AlmaLinux 9, Rocky Linux 9, RHEL 9 y Oracle Linux 9
Allí los paquetes se llaman de otra forma y llevan el sufijo .i686:
dnf -y update
dnf install -y --allowerasing glibc.i686 libstdc++.i686 tar file curl
Ambos añadidos son necesarios en una instalación mínima recién hecha, de lo contrario el comando se interrumpe. El motivo de --allowerasing: EL9 incluye curl-minimal, y el curl completo entra en conflicto con él. Sin ese parámetro, la llamada termina en AlmaLinux 9 y Rocky Linux 9 con package curl-minimal ... conflicts with curl provided by curl ... conflicting requests. Si borras curl por completo de la lista también llegas a tu objetivo, porque curl-minimal ya trae /usr/bin/curl. El motivo del dnf -y update previo: si el estado del sistema es más antiguo que los repositorios, el paquete i686 nuevo choca con el paquete de 64 bits instalado, medido en Rocky Linux 9 como file /usr/share/gcc-11/python/libstdcxx/v6/printers.py from install of libstdc++-11.5.0-14.el9.i686 conflicts with file from package libstdc++-11.4.1-2.1.el9.x86_64. En Oracle Linux 9 no aparece ninguno de los dos conflictos, allí ya está instalado el curl completo.
EPEL no hace falta, los paquetes están en los repositorios estándar. Si además quieres herramientas como htop, el camino está descrito en Instalar htop en AlmaLinux, Rocky y RHEL.
AlmaLinux 10, Rocky Linux 10 y RHEL 10 no sirven para SteamCMD
Esto no es un problema de configuración, sino un callejón sin salida: RHEL 10 y las distribuciones derivadas han eliminado por completo la arquitectura x86 de 32 bits. Allí no hay paquetes i686 en ningún repositorio, tampoco con --enablerepo=*, y el comando de instalación termina con No match for argument: glibc.i686. Como steamcmd.sh siempre llama al bootstrapper de 32 bits linux32/steamcmd, no hay manera de esquivarlo. Por eso, para un servidor de juego del lado de Red Hat hay que elegir la familia EL9, es decir AlmaLinux 9, Rocky Linux 9 u Oracle Linux 9.
Un segundo obstáculo en instalaciones EL muy escuetas: si solo está instalado util-linux-core, falta runuser, que se usa en toda esta guía. En ese caso ejecuta antes dnf install -y util-linux. En AlmaLinux 9, Rocky Linux 9, Oracle Linux 9 y en todos los sistemas Debian y Ubuntu, runuser ya está presente.
¿Por qué no usar simplemente el paquete steamcmd?
Ubuntu incluye steamcmd en el componente multiverse y Debian en non-free, y en ambos casos el paquete está compilado exclusivamente para la arquitectura i386. Por eso, en un servidor de 64 bits recién instalado te topas de forma fiable con:
E: Unable to locate package steamcmd
Para que llegue siquiera a ser un candidato, primero hay que habilitar el componente y activar la arquitectura ajena. En Ubuntu, multiverse ya está activo en la instalación estándar, así que allí bastan tres líneas:
dpkg --add-architecture i386
apt update
apt-cache policy steamcmd
En Debian falta además el componente. Sin él, apt-cache policy steamcmd no devuelve absolutamente ninguna salida, ni siquiera un mensaje de error. Antes hay que meter contrib y non-free en las fuentes de paquetes, desde Debian 12 normalmente en /etc/apt/sources.list.d/debian.sources, en la línea Components:. Solo después responde la consulta e informa en Debian 12 del candidato 0~20180105-5 de bookworm/non-free i386. El apt update entre el cambio de arquitectura y la consulta es obligatorio: sin esa ejecución no existen las listas de paquetes i386 y el candidato sigue siendo (none).
El esfuerzo rara vez merece la pena. El paquete de Debian es un wrapper muy antiguo (versión 0~20180105-5 en Debian 13) que de todos modos solo descarga el mismo bootstrapper que tú mismo consigues en dos líneas. La instalación manual es idéntica en todos los sistemas y, por tanto, mucho más fácil de documentar.
Instalar SteamCMD e interpretar el primer arranque
runuser -u steam -- curl -sSLo /home/steam/steamcmd/steamcmd_linux.tar.gz https://media.steampowered.com/client/installer/steamcmd_linux.tar.gz
runuser -u steam -- tar -xzf /home/steam/steamcmd/steamcmd_linux.tar.gz -C /home/steam/steamcmd
runuser -u steam -- /home/steam/steamcmd/steamcmd.sh +quit
El tercer comando es la prueba de verdad. En la primerísima llamada, SteamCMD se descarga a sí mismo, muestra un indicador de progreso y termina. Tiene este aspecto:
[ 0%] Checking for available update...
[----] Downloading update (0 of 58,393 KB)...
[100%] Download complete.
[----] Extracting package...
[----] Installing update...
[----] Verifying installation...
Steam Console Client (c) Valve Corporation - version 1751...
Loading Steam API...OK
Criterio de éxito: la última línea dice Loading Steam API...OK. Si en su lugar aparece Loading Steam API...FAILED o el proceso se interrumpe de inmediato, faltan las bibliotecas de 32 bits de la sección anterior. El texto típico es este:
steamcmd.sh: line 41: /home/steam/steamcmd/linux32/steamcmd: No such file or directory
Ese mensaje induce a error, porque el archivo sí existe. Lo que no se encuentra es el intérprete de 32 bits que necesita el binario. Puedes comprobarlo con file /home/steam/steamcmd/linux32/steamcmd: la salida dice ELF 32-bit LSB shared object, Intel 80386, ... interpreter /lib/ld-linux.so.2 y nombra exactamente el intérprete que falta. Si file falta él mismo con command not found, se olvidó en el paso de instalación de más arriba. La variante error while loading shared libraries: libstdc++.so.6 muestra el mismo problema, solo que un nivel más tarde.
Inicio de sesión anónimo frente a inicio de sesión con cuenta
La inmensa mayoría de los servidores dedicados se publican como aplicación de Steam propia y gratuita, y se pueden descargar sin credenciales:
+login anonymous
Ese es el caso normal y el camino que siempre deberías probar primero. Ninguna contraseña en el servidor, ningún Steam Guard, ninguna cuenta bloqueada tras una migración del servidor.
El inicio de sesión con cuenta solo hace falta cuando la build del servidor está ligada a la posesión del juego. Se reconoce por este mensaje:
ERROR! Failed to install app 'ID' (No subscription)
No subscription significa siempre lo mismo: esta cuenta no puede descargar esta app. Con un inicio de sesión anónimo significa que hace falta una cuenta real con el juego comprado. Con una cuenta real significa que falta la licencia o que se ha usado la App ID equivocada.
El inicio de sesión con cuenta es interactivo, porque Steam Guard pide un código:
/home/steam/steamcmd/steamcmd.sh +login tunombredeusuario
Tras la confirmación única queda un archivo sentry en ~/.steam, y a partir de ahí también funcionan las llamadas no interactivas. Tres detalles que duelen en la práctica: usa para este fin una cuenta de Steam separada que solo tenga la licencia del servidor. No escribas nunca la contraseña en un script de cron. Y cuenta con que Steam vuelva a pedir una confirmación tras un periodo largo de inactividad o tras un cambio de IP, con lo que una actualización automática se queda colgada en silencio.
Cosa aparte es el Game Server Login Token (GSLT). No tiene nada que ver con la descarga, sino con si el servidor en marcha aparece públicamente en la lista de servidores. En Counter-Strike 2 y otros títulos de Valve se genera en la cuenta de Steam y se introduce en la configuración del servidor, no en SteamCMD.
Instalar un juego: orden, validate y branches
SteamCMD procesa los argumentos + estrictamente de izquierda a derecha. De ahí se deriva la regla más importante de todas:
+force_install_dirtiene que ir antes de+app_update. Si va detrás, los archivos acaban en la ruta estándar y el directorio indicado se queda vacío.
Una llamada completa, aquí con el ejemplo del servidor de Valheim y la App ID 896660:
runuser -u steam -- mkdir -p /home/steam/valheim
runuser -u steam -- /home/steam/steamcmd/steamcmd.sh +force_install_dir /home/steam/valheim +login anonymous +app_update 896660 validate +quit
Ten en cuenta que validate se escribe sin el signo más: es un argumento de app_update y no un comando propio. validate compara cada archivo con la suma de comprobación del depot y vuelve a descargar todo lo que difiera. Tiene sentido en la instalación inicial, tras una descarga interrumpida y ante caídas extrañas. En cada actualización rutinaria es superfluo y caro, porque se lee el contenido completo. Conviene conocer dos efectos secundarios: los archivos que hayas modificado tú y que pertenezcan al depot se restablecen, y en juegos con mods dentro del directorio de instalación, validate puede eliminar archivos ajenos.
Como control de éxito sirve la línea final:
Success! App '896660' fully installed.
Otro branch, por ejemplo una rama pública de pruebas, se añade directamente a app_update:
+app_update 896660 -beta public-test validate
Para una rama protegida con contraseña se añade -betapassword. La vuelta a la versión estándar es -beta none, no basta con omitir el parámetro sin más, porque la elección del branch queda guardada en el manifiesto.
Cuando algo sale mal: los mensajes de error literales
SteamCMD informa de los problemas con un estado hexadecimal que, sin traducción, no dice nada. Los más frecuentes:
Error! App '...' state is 0x202 after update job: no hay suficiente espacio de almacenamiento. Compruébalo condf -h /home/steam. Recuerda que, además del directorio de destino, SteamCMD necesita espacio para la caché de descarga, por norma general en el mismo sistema de archivos bajosteamapps/downloading. En títulos grandes, el pico durante la actualización puede llegar a casi el doble del tamaño final. Si el disco está lleno, te ayuda Liberar espacio con el disco lleno en Linux.Error! App '...' state is 0x606 after update job: error de escritura. En nueve de cada diez casos son los permisos, no el hardware. El clásico: la primera ejecución se hizo como root y la segunda comosteam. Se repara conchown -R steam:steam /home/steam. Con enlaces simbólicos a una segunda unidad, el destino también tiene que pertenecer al usuario del servicio.Error! App '...' state is 0x402 after update job: no hay una conexión utilizable con los servidores de contenido de Steam. Casi siempre es una regla de firewall de salida o un problema con el servidor de nombres. SteamCMD necesita salida por TCP 443 y de 27015 a 27050.No subscription: cuestión de licencia, ver la sección anterior.Failed to load steamclient.soo[S_API FAIL] SteamAPI_Init(): el binario del servidor busca la biblioteca de Steam en una ubicación fija que SteamCMD no rellena. Están afectados prácticamente todos los servidores de Unreal Engine, además de Rust, Palworld y V Rising. La solución son dos enlaces en el directorio personal del usuario del servicio.
runuser -u steam -- mkdir -p /home/steam/.steam/sdk64
runuser -u steam -- ln -sf /home/steam/steamcmd/linux64/steamclient.so /home/steam/.steam/sdk64/steamclient.so
runuser -u steam -- mkdir -p /home/steam/.steam/sdk32
runuser -u steam -- ln -sf /home/steam/steamcmd/linux32/steamclient.so /home/steam/.steam/sdk32/steamclient.so
Como son enlaces al directorio de SteamCMD, siguen siendo válidos después de que SteamCMD se actualice a sí mismo. Un fallo derivado muy habitual es crear esos directorios como root, con lo que el servicio después no puede leerlos.
Si una descarga se queda atascada de forma permanente, el último recurso es borrar steamapps/appmanifest_<ID>.acf en el directorio de instalación. Después SteamCMD considera que la app no está instalada y la descarga entera de nuevo.
Automatizar las actualizaciones sin reiniciar el servidor sin motivo
La recomendación más extendida es ejecutar app_update una vez al día por cron y reiniciar el servicio. Eso cuesta una interrupción cada día, aunque no haya ninguna actualización. Es mejor comparar la build ID. La instalada está en el archivo de manifiesto, la actual la entrega app_info_print:
runuser -u steam -- /home/steam/steamcmd/steamcmd.sh +login anonymous +app_info_update 1 +app_info_print 896660 +quit
De ahí sale un script en /usr/local/sbin/steam-update.sh:
#!/bin/bash
set -euo pipefail
APPID=896660
DIR=/home/steam/valheim
CMD=/home/steam/steamcmd/steamcmd.sh
UNIT=valheim
MANIFEST="$DIR/steamapps/appmanifest_${APPID}.acf"
installed=$(awk '/"buildid"/ {gsub(/"/,"",$2); print $2; exit}' "$MANIFEST" 2>/dev/null || echo 0)
latest=$(runuser -u steam -- "$CMD" +login anonymous +app_info_update 1 +app_info_print "$APPID" +quit \
| awk '/"public"/{f=1} f && /"buildid"/ {gsub(/"/,"",$2); print $2; exit}')
if [ -z "$latest" ]; then
echo "No se ha podido determinar la build ID actual, se aborta."
exit 1
fi
if [ "$installed" = "$latest" ]; then
echo "Al día (build $installed), sin reinicio."
exit 0
fi
echo "Actualizando de $installed a $latest"
systemctl stop "$UNIT"
runuser -u steam -- "$CMD" +force_install_dir "$DIR" +login anonymous +app_update "$APPID" +quit
systemctl start "$UNIT"
El script solo reinicia cuando algo ha cambiado de verdad, y se interrumpe limpiamente cuando Steam no responde en ese momento. Sin esa comprobación, un resultado de consulta vacío se interpretaría como actualización y el servidor se detendría sin motivo. Se ejecuta por cron o, mejor todavía, mediante un timer de systemd; los fundamentos están en Configurar un cronjob en Linux.
Ten en cuenta que muchos juegos, tras una actualización del servidor, exigen también clientes actualizados. Una actualización automática en plena hora punta de juego echa fuera a todos los jugadores. Programa la ejecución para las primeras horas de la mañana.
Funcionamiento como servicio systemd
Un servidor de juego en una sesión de screen no sobrevive a un reinicio. Una unidad en /etc/systemd/system/valheim.service lo resuelve:
[Unit]
Description=Valheim Dedicated Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=steam
Group=steam
WorkingDirectory=/home/steam/valheim
Environment=LD_LIBRARY_PATH=/home/steam/valheim/linux64
Environment=SteamAppId=892970
ExecStart=/home/steam/valheim/valheim_server.x86_64 -nographics -batchmode -name "KernelHost" -port 2456 -world "Dedicated" -password "cambiaEsto"
Restart=on-failure
RestartSec=10
KillSignal=SIGINT
TimeoutStopSec=90
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now valheim
systemctl status valheim
Dos líneas de ahí son más importantes de lo que parecen. KillSignal=SIGINT hace que el servidor guarde la partida al detenerse, porque bastantes servidores de juego ignoran SIGTERM y pierden el progreso de los últimos minutos si se los mata de golpe. TimeoutStopSec le da tiempo para ello. Encontrarás una explicación detallada de todos los campos en Crear un servicio systemd, y el procedimiento para un servidor Java en Iniciar un servidor Minecraft automáticamente.
Si el servidor muere nada más arrancar por falta de memoria RAM, ayuda echar un vistazo a Configurar swap. Los puertos van después al firewall, ver Configurar UFW, teniendo en cuenta que los servidores de juego casi siempre necesitan UDP y que una entrada solo de TCP suele ser el motivo por el que el servidor funciona pero nadie logra conectarse.
App IDs de los juegos habituales
La ID es lo único que cambia entre un juego y otro. Se pueden descargar de forma anónima, entre otros:
- 232250 Team Fortress 2
- 4020 Garry's Mod
- 222860 Left 4 Dead 2
- 730 Counter-Strike 2 (cliente y servidor son la misma app desde el cambio de CS:GO, así que la descarga es grande en consecuencia)
- 258550 Rust
- 376030 ARK: Survival Evolved
- 896660 Valheim
- 2394010 Palworld
- 2278520 Enshrouded
- 1829350 V Rising
- 294420 7 Days to Die
- 380870 Project Zomboid
- 1690800 Satisfactory
- 581330 Insurgency: Sandstorm
- 233780 Arma 3
- 1007 Steamworks SDK Redistributables, diminuto y por eso ideal como prueba de funcionamiento de la instalación
No confundas la app del servidor con la app del juego. En ARK, por ejemplo, 346110 es el juego y 376030 el servidor. Si buscas una ID, la encontrarás en la Dedicated Servers List del Valve Developer Wiki o a través de SteamDB. La prueba rápida es siempre la misma: un app_update anónimo, y si aparece No subscription, era la ID del cliente.
Cómo reconocer que realmente funciona
Cuatro comprobaciones, en este orden:
- Los archivos están ahí.
du -sh /home/steam/valheimtiene que mostrar un tamaño plausible, y ensteamapps/appmanifest_896660.acfhay unbuildid. Un directorio de unos pocos megabytes significa descarga interrumpida. - El proceso vive más de un minuto.
systemctl status valheimmuestraactive (running). Un servicio que se reinicia cada segundo se queda enactivating (auto-restart), y entoncesjournalctl -u valheim -n 50te da el motivo. - El puerto está abierto, y además como UDP.
ss -ulpn | grep 2456tiene que nombrar el proceso. Que no se vea nada significa: el servidor sigue inicializándose o está enlazado a la dirección equivocada. - Accesible desde fuera. Solo después comprueba el firewall y conéctate desde el propio juego. Muchos títulos necesitan además un puerto de consulta; en Valheim es el puerto del servidor más uno.
Si estos cuatro puntos están en orden, la base está bien y todo lo demás es configuración del juego. En un servidor root de KernelHost, en el centro de datos maincubes de Fráncfort del Meno, se suma la protección DDoS de nuestra propia red, algo especialmente relevante en servidores de juego listados públicamente, porque una lista pública de servidores deja la dirección IP a la vista de cualquiera. Encontrarás el trasfondo en Proteger el servidor frente a ataques DDoS.
Preguntas frecuentes
¿Por qué no arranca SteamCMD en mi servidor de 64 bits?
¿Necesito una cuenta de Steam para un servidor de juego?
¿Qué significa "App state is 0x606 after update job"?
¿Debo añadir validate en cada actualización?
¿Cómo actualizo automáticamente sin reiniciar el servidor cada día?
¿Por qué apt no encuentra el paquete steamcmd?
2026 KernelHost GmbH. Todos los derechos reservados. Esta guía está protegida por derechos de autor. Su publicación en otros sitios web, aunque sea de forma parcial o modificada, no está permitida sin nuestro consentimiento por escrito. Las citas con indicación de la fuente y un enlace son muy bienvenidas.

