Instalar um servidor de jogos com o SteamCMD
O SteamCMD é a base comum de quase todos os servidores de jogos na Steam. Este guia mostra a instalação, o início de sessão anónimo, o app_update com validate, o funcionamento como serviço systemd e os erros típicos.
Quem opera um servidor de jogos num servidor root próprio acaba quase sempre na mesma ferramenta: SteamCMD. Seja Valheim, Rust, Counter-Strike 2, Palworld, Enshrouded ou ARK, os ficheiros do servidor estão alojados na Valve e são obtidos através do mesmo cliente de linha de comandos. Depois de configurar o SteamCMD uma vez de forma limpa, instala qualquer outro jogo apenas com um número diferente.
Este guia cobre exatamente os pontos onde os tutoriais mais curtos param: as bibliotecas de 32 bits em sistemas de 64 bits, as diferenças entre Debian, Ubuntu e a família Red Hat, as mensagens de erro na sua forma literal, um procedimento de atualização que não reinicia o servidor a cada execução do cron, e o funcionamento como serviço systemd.
O que o SteamCMD é e o que não é
O SteamCMD é o Steam Console Client, uma versão reduzida do cliente Steam para a linha de comandos, sem interface gráfica. Faz bem exatamente uma coisa: descarregar aplicações da rede Steam, atualizá-las e verificar os respetivos ficheiros. Não inicia nenhum servidor, não configura nada e desconhece a lógica do jogo. Depois do download, os ficheiros do servidor ficam num diretório e, a partir daí, a vez é do jogo em questão.
Importante para compreender toda a questão das bibliotecas: o bootstrapper do SteamCMD continua a ser, até hoje, um programa de 32 bits. Num sistema puramente de 64 bits faltam-lhe as bibliotecas de runtime adequadas, e é precisamente aí que o primeiro arranque falha para a maioria das pessoas. Já os ficheiros do servidor descarregados são, nos jogos modernos, quase sempre de 64 bits.
Preparação: um utilizador próprio em vez de root
Os processos de um servidor de jogos nunca correm como root. Aceitam ligações vindas da Internet, em muitos títulos descarregam mods da Steam Workshop e executam código de terceiros. Um utilizador próprio e sem privilégios custa três comandos e limita os estragos.
useradd -m -d /home/steam -s /bin/bash steam
mkdir -p /home/steam/steamcmd
chown -R steam:steam /home/steam/steamcmd
O SteamCMD avisa expressamente contra isso quando é iniciado como root. Quem ignora o aviso volta a encontrar o problema mais tarde: assim que um diretório passar a pertencer ao root, a execução posterior com o utilizador steam falha com um erro de escrita, e a mensagem de erro não aponta para a causa.
Todos os comandos seguintes deste artigo são introduzidos como root e mudam para o utilizador de serviço através de runuser -u steam --. Em sistemas com sudo funciona igualmente sudo -u steam. Quem quiser tratar primeiro da proteção básica encontra os fundamentos em Configurar um servidor root novo e Proteger o SSH.
As bibliotecas de 32 bits, diferentes conforme o sistema
É aqui que as distribuições se separam, e as listas de comandos genéricas que circulam na Internet estão regularmente erradas neste ponto.
Debian 12, Debian 13, Ubuntu 22.04 e Ubuntu 24.04
Nos quatro sistemas basta o pacote lib32gcc-s1 do arquivo principal. É um pacote amd64 que traz consigo o runtime de 32 bits e não precisa de nenhuma arquitetura i386 adicional:
apt update
apt install -y ca-certificates curl tar file lib32gcc-s1 lib32stdc++6
O lib32stdc++6 nem sempre é necessário para o próprio SteamCMD, mas vários binários de servidor mais antigos (tudo o que assenta na Source Engine, títulos HLDS, alguns servidores Unity) exigem-no. Instalá-lo logo poupa um diagnóstico posterior. O file não vem em nenhuma das imagens mínimas e é preciso mais abaixo para a análise de erros, por isso consta desde já na lista.
AlmaLinux 9, Rocky Linux 9, RHEL 9 e Oracle Linux 9
Aí os pacotes têm outros nomes e usam o sufixo .i686:
dnf -y update
dnf install -y --allowerasing glibc.i686 libstdc++.i686 tar file curl
Ambos os acréscimos são necessários numa instalação mínima acabada de fazer, caso contrário o comando aborta. A razão para --allowerasing: o EL9 traz o curl-minimal, e o curl completo colide com ele. Sem esse parâmetro, a chamada termina no AlmaLinux 9 e no Rocky Linux 9 com package curl-minimal ... conflicts with curl provided by curl ... conflicting requests. Quem retirar o curl por completo da lista também chega ao objetivo, porque o curl-minimal já fornece o /usr/bin/curl. A razão para o dnf -y update prévio: se o estado do sistema for mais antigo do que os repositórios, o pacote i686 recente colide com o pacote de 64 bits instalado, medido no 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. No Oracle Linux 9 não ocorre nenhum dos dois conflitos, porque aí já está instalado o curl completo.
O EPEL não é necessário, os pacotes estão nos repositórios padrão. Quem quiser adicionalmente ferramentas como o htop encontra o caminho em Instalar o htop no AlmaLinux, Rocky e RHEL.
AlmaLinux 10, Rocky Linux 10 e RHEL 10 não servem para o SteamCMD
Não se trata de um problema de configuração, mas de um beco sem saída: o RHEL 10 e as distribuições dele derivadas eliminaram por completo a arquitetura x86 de 32 bits. Aí não existem pacotes i686 em nenhum repositório, nem sequer com --enablerepo=*, e o comando de instalação termina com No match for argument: glibc.i686. Como o steamcmd.sh chama sempre o bootstrapper de 32 bits linux32/steamcmd, isto não tem forma de ser contornado. Para um servidor de jogos do lado da Red Hat deve, por isso, escolher a família EL9, ou seja, AlmaLinux 9, Rocky Linux 9 ou Oracle Linux 9.
Um segundo obstáculo em instalações EL muito reduzidas: se estiver apenas instalado o util-linux-core, falta o runuser, que é usado ao longo de todo este guia. Nesse caso execute antes dnf install -y util-linux. No AlmaLinux 9, Rocky Linux 9 e Oracle Linux 9, bem como em todos os sistemas Debian e Ubuntu, o runuser já está presente.
Porque não usar simplesmente o pacote steamcmd?
O Ubuntu tem o steamcmd no componente multiverse e o Debian em non-free, e em ambos os casos o pacote é compilado exclusivamente para a arquitetura i386. Por isso, num servidor de 64 bits acabado de instalar, esbarra-se de forma fiável em:
E: Unable to locate package steamcmd
Para que o pacote sequer se torne um candidato, seria preciso ativar primeiro o componente e a arquitetura estrangeira. No Ubuntu, o multiverse já está ativo na instalação padrão, aí bastam estas três linhas:
dpkg --add-architecture i386
apt update
apt-cache policy steamcmd
No Debian falta adicionalmente o componente. Sem ele, o apt-cache policy steamcmd não devolve saída nenhuma, ou seja, nem sequer uma mensagem de erro. Antes disso é preciso colocar contrib e non-free nas fontes de pacotes, desde o Debian 12 normalmente em /etc/apt/sources.list.d/debian.sources, na linha Components:. Só depois a consulta funciona e indica, no Debian 12, o candidato 0~20180105-5 a partir de bookworm/non-free i386. O apt update entre a ativação da arquitetura e a consulta é obrigatório: sem essa execução, as listas de pacotes i386 não existem e o candidato continua a ser (none).
O esforço raramente compensa. O pacote do Debian é um wrapper muito antigo (versão 0~20180105-5 no Debian 13) que, de qualquer forma, apenas descarrega o mesmo bootstrapper que se obtém em duas linhas. A instalação manual é idêntica em todos os sistemas e, por isso, mais fácil de documentar.
Instalar o SteamCMD e interpretar o primeiro 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
O terceiro comando é o verdadeiro teste. Na primeiríssima chamada, o SteamCMD descarrega-se a si próprio, mostra uma indicação de progresso e termina. O aspeto é este:
[ 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
Critério de sucesso: a última linha diz Loading Steam API...OK. Se em vez disso surgir Loading Steam API...FAILED, ou se o processo abortar de imediato, faltam as bibliotecas de 32 bits da secção anterior. O texto típico é este:
steamcmd.sh: line 41: /home/steam/steamcmd/linux32/steamcmd: No such file or directory
Esta mensagem é enganadora, porque o ficheiro existe mesmo. O que não é encontrado é o interpretador de 32 bits de que o binário precisa. Pode verificá-lo com file /home/steam/steamcmd/linux32/steamcmd: a saída diz ELF 32-bit LSB shared object, Intel 80386, ... interpreter /lib/ld-linux.so.2 e nomeia assim exatamente o interpretador em falta. Se o próprio file faltar, com command not found, foi esquecido no passo de instalação acima. A variante error while loading shared libraries: libstdc++.so.6 mostra o mesmo problema, apenas um nível mais tarde.
Início de sessão anónimo ou com conta
A grande maioria dos servidores dedicados é publicada como aplicação Steam própria e gratuita, podendo ser descarregada sem credenciais:
+login anonymous
Este é o caso normal e o caminho que deve tentar sempre em primeiro lugar. Nenhuma palavra-passe no servidor, nenhum Steam Guard, nenhuma conta bloqueada depois de uma mudança de servidor.
O início de sessão com conta só é necessário quando a build do servidor está ligada à posse do jogo. Reconhece-se por esta mensagem:
ERROR! Failed to install app 'ID' (No subscription)
No subscription significa sempre: esta conta não tem permissão para descarregar esta aplicação. Com início de sessão anónimo, quer dizer que é preciso uma conta real com o jogo comprado. Com uma conta real, quer dizer que falta a licença ou que foi utilizado o App ID errado.
O início de sessão com conta decorre de forma interativa, porque o Steam Guard exige um código:
/home/steam/steamcmd/steamcmd.sh +login oseunomedeutilizador
Após a confirmação única fica um ficheiro sentry em ~/.steam e, a partir daí, também as chamadas não interativas funcionam. Três pontos que costumam doer na prática: use para este efeito uma conta Steam separada, que detenha apenas a licença do servidor. Nunca escreva a palavra-passe num script de cron. E conte com o facto de o Steam voltar a pedir uma confirmação após um período longo de inatividade ou uma mudança de IP, o que faz com que uma atualização automática fique bloqueada em silêncio.
À parte disso está o Game Server Login Token (GSLT). Não tem nada a ver com o download, mas sim com a questão de o servidor em execução aparecer publicamente na lista de servidores. No Counter-Strike 2 e noutros títulos da Valve, é gerado na conta Steam e introduzido na configuração do servidor, não no SteamCMD.
Instalar um jogo: ordem, validate e branches
O SteamCMD processa os argumentos + estritamente da esquerda para a direita. Daí decorre a regra mais importante de todas:
+force_install_dirtem de estar antes de+app_update. Se estiver depois, os ficheiros vão parar ao caminho padrão e o diretório indicado fica vazio.
Uma chamada completa, aqui com o exemplo do servidor de Valheim com o 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
Repare que validate se escreve sem sinal de mais: é um argumento de app_update e não um comando próprio. O validate compara cada ficheiro com a soma de verificação do depot e volta a descarregar as divergências. Faz sentido na primeira instalação, depois de um download interrompido e em falhas estranhas. Em cada atualização de rotina é supérfluo e caro, porque todo o conteúdo é lido. Convém conhecer dois efeitos secundários: os ficheiros alterados por si que pertençam ao depot são repostos e, em jogos com mods no diretório de instalação, o validate pode remover ficheiros externos.
Como controlo de sucesso serve a linha final:
Success! App '896660' fully installed.
Um outro branch, por exemplo um ramo de teste público, é acrescentado diretamente a app_update:
+app_update 896660 -beta public-test validate
Para um ramo protegido por palavra-passe acresce -betapassword. O caminho de regresso à versão padrão é -beta none; omitir simplesmente o parâmetro não chega, porque a escolha do branch fica guardada no manifesto.
Quando corre mal: as mensagens de erro na sua forma literal
O SteamCMD comunica os problemas como um estado em hexadecimal que, sem tradução, não diz nada. Os mais frequentes:
Error! App '...' state is 0x202 after update job: espaço de armazenamento insuficiente. Verifique comdf -h /home/steam. Lembre-se de que o SteamCMD precisa, além do diretório de destino, de espaço para a cache de download, regra geral no mesmo sistema de ficheiros emsteamapps/downloading. Em títulos grandes, a necessidade máxima durante a atualização pode chegar quase ao dobro do tamanho final. Se o disco estiver cheio, ajuda Disco cheio no Linux: libertar espaço.Error! App '...' state is 0x606 after update job: erro de escrita. Em nove de cada dez casos são as permissões, não o hardware. Clássico: a primeira execução foi feita como root e a segunda comosteam. A reparação faz-se comchown -R steam:steam /home/steam. Em ligações simbólicas para uma segunda unidade, também o destino tem de pertencer ao utilizador de serviço.Error! App '...' state is 0x402 after update job: nenhuma ligação utilizável aos servidores de conteúdos da Steam. Na maioria das vezes é uma regra de firewall de saída ou um problema de servidor de nomes. O SteamCMD precisa, no sentido de saída, de TCP 443 e das portas 27015 a 27050.No subscription: questão de licença, ver a secção anterior.Failed to load steamclient.soou[S_API FAIL] SteamAPI_Init(): o binário do servidor procura a biblioteca da Steam num local fixo que o SteamCMD não preenche. São afetados praticamente todos os servidores baseados na Unreal Engine, bem como Rust, Palworld e V Rising. A solução são duas ligações simbólicas no diretório pessoal do utilizador de serviço.
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 se trata de ligações para o diretório do SteamCMD, mantêm-se válidas depois de uma atualização automática do próprio SteamCMD. Um erro subsequente frequente é criar estes diretórios como root, o que impede o serviço de os ler mais tarde.
Se um download ficar permanentemente encravado, o último recurso é apagar steamapps/appmanifest_<ID>.acf no diretório de instalação. A partir daí, o SteamCMD considera a aplicação como não instalada e volta a descarregá-la por completo.
Automatizar as atualizações sem reiniciar o servidor sem necessidade
A recomendação mais divulgada é executar app_update uma vez por dia através do cron e reiniciar o serviço. Isso custa uma interrupção diária, mesmo quando não existe atualização nenhuma. Melhor é comparar o build ID. O instalado está no ficheiro de manifesto, o atual é fornecido por app_info_print:
runuser -u steam -- /home/steam/steamcmd/steamcmd.sh +login anonymous +app_info_update 1 +app_info_print 896660 +quit
Daí resulta um script em /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 "Não foi possível determinar o build ID atual, a abortar."
exit 1
fi
if [ "$installed" = "$latest" ]; then
echo "Atualizado (build $installed), sem reinício."
exit 0
fi
echo "Atualização de $installed para $latest"
systemctl stop "$UNIT"
runuser -u steam -- "$CMD" +force_install_dir "$DIR" +login anonymous +app_update "$APPID" +quit
systemctl start "$UNIT"
O script só reinicia quando algo mudou realmente e aborta de forma limpa quando a Steam não está a responder. Sem essa verificação, um resultado de consulta vazio seria interpretado como atualização e o servidor seria parado sem motivo. A execução faz-se por cron ou, melhor ainda, por um timer do systemd; os fundamentos estão em Configurar um cronjob no Linux.
Tenha em conta que muitos jogos, depois de uma atualização do servidor, exigem também clientes atualizados. Uma atualização automática a meio do horário de maior atividade expulsa todos os jogadores. Agende a execução para as primeiras horas da manhã.
Funcionamento como serviço systemd
Um servidor de jogos numa sessão do screen não sobrevive a um reinício. Uma unidade em /etc/systemd/system/valheim.service resolve isso:
[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 "altereIsto"
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
Duas linhas são mais importantes do que parecem. O KillSignal=SIGINT garante que o servidor grava ao parar, porque vários servidores de jogos ignoram o SIGTERM e perdem, num encerramento forçado, o progresso dos últimos minutos. O TimeoutStopSec dá-lhe tempo para isso. Uma explicação detalhada de todos os campos encontra em Criar um serviço systemd, e o procedimento no caso de um servidor Java em Iniciar o servidor Minecraft automaticamente.
Se o servidor morrer logo no arranque por falta de memória, ajuda uma vista de olhos em Criar swap. As portas pertencem depois à firewall, ver Configurar a UFW, sendo que os servidores de jogos precisam quase sempre de UDP e uma entrada apenas para TCP é tipicamente a razão pela qual o servidor corre mas ninguém consegue ligar-se.
App IDs dos jogos mais comuns
O ID é o único ponto que muda de jogo para jogo. Podem ser descarregados anonimamente, entre outros:
- 232250 Team Fortress 2
- 4020 Garry's Mod
- 222860 Left 4 Dead 2
- 730 Counter-Strike 2 (desde a passagem do CS:GO, cliente e servidor são a mesma aplicação, pelo que o download é correspondentemente grande)
- 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, minúsculo e por isso ideal como teste de funcionamento da instalação
Não confunda a aplicação do servidor com a aplicação do jogo. No ARK, por exemplo, 346110 é o jogo e 376030 é o servidor. Quem procura um ID encontra-o na Dedicated Servers List do Valve Developer Wiki ou através do SteamDB. O teste rápido é sempre o mesmo: um app_update anónimo e, se surgir No subscription, era o ID do cliente.
Como reconhecer que está mesmo a funcionar
Quatro verificações, por esta ordem:
- Ficheiros presentes. O
du -sh /home/steam/valheimtem de mostrar um tamanho plausível e, emsteamapps/appmanifest_896660.acf, existe umabuildid. Um diretório com poucos megabytes significa download interrompido. - O processo vive mais do que um minuto. O
systemctl status valheimmostraactive (running). Um serviço que reinicia de segundo a segundo fica emactivating (auto-restart), e nesse caso ojournalctl -u valheim -n 50dá o motivo. - A porta está aberta, e como UDP. O
ss -ulpn | grep 2456tem de indicar o processo. Não ver nada significa: o servidor ainda está a inicializar ou foi ligado ao endereço errado. - Acessível a partir do exterior. Só depois disso verifique a firewall e ligue-se a partir do jogo. Muitos títulos precisam adicionalmente de uma porta de query; no Valheim é a porta do servidor mais um.
Se estes quatro pontos estiverem certos, a base está em ordem e todo o resto é configuração do jogo. Num servidor root da KernelHost, no datacenter maincubes em Frankfurt am Main, acresce a proteção DDoS a partir da rede própria, o que é especialmente relevante em servidores de jogos listados publicamente, porque uma lista pública de servidores torna o endereço IP visível para toda a gente. Encontra o contexto em Proteger o servidor contra ataques DDoS.
Perguntas frequentes
Porque é que o SteamCMD não arranca no meu servidor de 64 bits?
Preciso de uma conta Steam para um servidor de jogos?
O que significa "App state is 0x606 after update job"?
Devo indicar validate em todas as atualizações?
Como atualizo automaticamente sem reiniciar o servidor todos os dias?
Porque é que o apt não encontra o pacote steamcmd?
2026 KernelHost GmbH. Todos os direitos reservados. Este guia está protegido por direitos de autor. A sua republicação noutros sites, na íntegra, em parte ou de forma editada, não é permitida sem o nosso consentimento por escrito. Citações com indicação da fonte e ligação são expressamente bem-vindas.

