Un VPS con suficiente memoria puede alojar varios servidores de juegos a la vez, siempre que cada uno tenga sus propios puertos, sus datos separados y un límite de recursos que impida que uno deje sin memoria a los demás. En este tutorial usarás Docker Compose en Ubuntu 24.04 para levantar dos servidores de Minecraft Java (supervivencia y creativo) y un servidor dedicado de Valheim. Al terminar sabrás añadir, parar y respaldar cada servidor de forma independiente.

Requisitos previos

  • Un VPS con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 4 vCPU y 12 GB de RAM para los tres servidores de este ejemplo.
  • Un usuario no root con privilegios sudo.
  • Docker Engine y el plugin de Docker Compose instalados desde el repositorio oficial de Docker. Si aún no los tienes, sigue la guía de instalación de Docker de CubePath.
  • Tu usuario en el grupo docker, o anteponer sudo a los comandos docker.

Paso 1: Calcular los recursos

La memoria es el recurso que se agota primero. Cada servidor necesita su memoria de juego más un margen para el propio proceso, y el sistema operativo necesita al menos 1 GB libre. Estas cifras son un punto de partida razonable:

ServidorJugadoresRAM asignadaCPU
Minecraft Java (Paper, vanilla)10 a 203 a 4 GB1 a 2 núcleos
Minecraft Java con mods10 a 206 a 8 GB2 núcleos
Valheimhasta 103 a 4 GB2 núcleos

Para este tutorial:

  • mc-survival: 4 GB de límite, 3 GB de heap de Java, 2 CPU.
  • mc-creative: 3 GB de límite, 2 GB de heap de Java, 1 CPU.
  • valheim: 4 GB de límite, 2 CPU.

En total son 11 GB como máximo, lo que deja 1 GB para el sistema en un VPS de 12 GB. Los límites de CPU pueden sumar más que los núcleos reales, porque rara vez todos los servidores están a plena carga a la vez; los de memoria no.

Comprueba los recursos de tu servidor:

nproc
free -h
df -h /

Paso 2: Crear la estructura de directorios

Guarda todo en un único directorio, con una carpeta de datos por servidor. Así cada mundo se respalda o se borra sin afectar a los demás:

mkdir -p ~/gameservers/{mc-survival,mc-creative,valheim/config,valheim/data}
cd ~/gameservers

Paso 3: Definir los servidores en Docker Compose

Usarás dos imágenes de la comunidad muy mantenidas: itzg/minecraft-server, que descarga y configura el servidor de Minecraft a partir de variables de entorno, y lloesche/valheim-server, que instala el servidor dedicado de Valheim con SteamCMD.

Cada Minecraft escucha en el puerto 25565 dentro de su contenedor; en el host, el segundo se publica en el 25566 para que no choquen. Valheim usa los puertos UDP 2456 y 2457.

Crea el archivo de Compose:

nano ~/gameservers/compose.yaml

Añade este contenido. Sustituye your_valheim_password por una contraseña de al menos 5 caracteres que no contenga el nombre del servidor:

services:
  mc-survival:
    image: itzg/minecraft-server:latest
    container_name: mc-survival
    restart: unless-stopped
    environment:
      EULA: "TRUE"
      TYPE: "PAPER"
      VERSION: "LATEST"
      MEMORY: "3G"
      MOTD: "Servidor de supervivencia"
      DIFFICULTY: "normal"
      MAX_PLAYERS: "20"
      TZ: "Europe/Madrid"
    ports:
      - "25565:25565/tcp"
    volumes:
      - ./mc-survival:/data
    mem_limit: 4g
    cpus: 2

  mc-creative:
    image: itzg/minecraft-server:latest
    container_name: mc-creative
    restart: unless-stopped
    environment:
      EULA: "TRUE"
      TYPE: "PAPER"
      VERSION: "LATEST"
      MEMORY: "2G"
      MOTD: "Servidor creativo"
      MODE: "creative"
      MAX_PLAYERS: "10"
      TZ: "Europe/Madrid"
    ports:
      - "25566:25565/tcp"
    volumes:
      - ./mc-creative:/data
    mem_limit: 3g
    cpus: 1

  valheim:
    image: lloesche/valheim-server:latest
    container_name: valheim
    restart: unless-stopped
    stop_grace_period: 2m
    cap_add:
      - sys_nice
    environment:
      SERVER_NAME: "Mi servidor Valheim"
      WORLD_NAME: "Midgard"
      SERVER_PASS: "your_valheim_password"
      SERVER_PUBLIC: "true"
      TZ: "Europe/Madrid"
    ports:
      - "2456-2457:2456-2457/udp"
    volumes:
      - ./valheim/config:/config
      - ./valheim/data:/opt/valheim
    mem_limit: 4g
    cpus: 2

Qué hace cada ajuste importante:

  • EULA: "TRUE" acepta la licencia de Minecraft; sin ella el servidor no arranca. Hazlo solo si has leído y aceptas el EULA de Mojang.
  • MEMORY fija el heap de Java. Déjalo siempre por debajo de mem_limit, porque la JVM usa memoria adicional fuera del heap. Si ambos valores coinciden, el kernel matará el contenedor por falta de memoria.
  • mem_limit y cpus son límites duros de Docker: un servidor con una fuga de memoria se reinicia solo, en lugar de tumbar a los otros dos.
  • restart: unless-stopped arranca los servidores con el sistema, salvo los que hayas parado a mano.
  • stop_grace_period: 2m da tiempo a Valheim para guardar el mundo al detenerse.

Valida el archivo antes de arrancar:

docker compose config --quiet && echo "compose.yaml correcto"

Paso 4: Arrancar los servidores

Descarga las imágenes y levanta los tres servidores en segundo plano:

docker compose up -d

El primer arranque tarda varios minutos: Minecraft descarga Paper y genera el mundo, y Valheim descarga el servidor dedicado (más de 1 GB). Sigue el progreso de cada uno:

docker compose logs -f mc-survival

El servidor de Minecraft está listo cuando aparece una línea como esta (pulsa Ctrl+C para salir de los logs):

mc-survival  | [12:04:31 INFO]: Done (18.402s)! For help, type "help"

Comprueba el estado de todos los contenedores:

docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
NAME          STATUS                   PORTS
mc-creative   Up 3 minutes (healthy)   0.0.0.0:25566->25565/tcp
mc-survival   Up 3 minutes (healthy)   0.0.0.0:25565->25565/tcp
valheim       Up 3 minutes             0.0.0.0:2456-2457->2456-2457/udp

Las imágenes de Minecraft incluyen rcon-cli para enviar comandos a la consola del servidor. Úsalo para confirmar que responde:

docker exec mc-survival rcon-cli list
There are 0 of a max of 20 players online:

Paso 5: Abrir los puertos en el firewall

Docker publica los puertos insertando sus propias reglas en iptables, que se evalúan antes que las de UFW. Eso significa que los puertos del archivo de Compose quedan accesibles desde Internet aunque UFW no los permita. Aun así, añade las reglas en UFW para que el firewall documente lo que está expuesto y siga protegiendo SSH:

sudo ufw allow OpenSSH
sudo ufw allow 25565:25566/tcp comment 'Minecraft'
sudo ufw allow 2456:2457/udp comment 'Valheim'
sudo ufw enable
sudo ufw status

Conéctate desde tu cliente de Minecraft a your_server_ip (supervivencia) y a your_server_ip:25566 (creativo). En Valheim, añade el servidor como your_server_ip:2456 desde la lista de servidores.

Paso 6: Vigilar el consumo de recursos

Muestra el uso de CPU y memoria de cada contenedor frente a su límite:

docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"
NAME          CPU %     MEM USAGE / LIMIT   MEM %
mc-survival   38.52%    3.21GiB / 4GiB      80.25%
mc-creative   6.10%     2.14GiB / 3GiB      71.33%
valheim       55.20%    2.87GiB / 4GiB      71.75%

Una CPU por encima del 100 % en un contenedor con cpus: 2 es normal (100 % equivale a un núcleo). Fíjate sobre todo en la memoria: si un contenedor ronda el 95 % de su límite de forma constante, súbelo o reduce el heap. Para saber si Docker ha matado algún contenedor por memoria:

docker inspect --format '{{.Name}} OOMKilled={{.State.OOMKilled}} Restarts={{.RestartCount}}' mc-survival mc-creative valheim

Paso 7: Gestionar cada servidor por separado

Todos los comandos se ejecutan desde ~/gameservers y aceptan el nombre de un servicio para actuar solo sobre él.

Reinicia un servidor sin tocar los demás:

docker compose restart mc-creative

Detén un servidor que no se usa para liberar su memoria:

docker compose stop valheim

Actualiza las imágenes y recrea solo los contenedores que hayan cambiado:

docker compose pull
docker compose up -d

Para añadir un cuarto servidor, copia un bloque de servicio en compose.yaml, cambia el nombre, el directorio de datos y el puerto del host (por ejemplo, 25567:25565/tcp), abre ese puerto en UFW y ejecuta docker compose up -d.

Paso 8: Hacer copias de seguridad de los mundos

Copiar los archivos de un mundo mientras el servidor escribe en ellos puede dar lugar a una copia corrupta. Para Minecraft, desactiva el guardado automático, fuerza un guardado, copia y vuelve a activarlo:

mkdir -p ~/backups
docker exec mc-survival rcon-cli save-off
docker exec mc-survival rcon-cli save-all flush
tar -czf ~/backups/mc-survival-$(date +%F).tar.gz -C ~/gameservers mc-survival
docker exec mc-survival rcon-cli save-on

Valheim guarda el mundo al detenerse, así que la forma más segura es pararlo unos segundos:

cd ~/gameservers
docker compose stop valheim
tar -czf ~/backups/valheim-$(date +%F).tar.gz -C ~/gameservers valheim/config
docker compose start valheim

Comprueba que las copias contienen los mundos:

tar -tzf ~/backups/mc-survival-$(date +%F).tar.gz | head

Guarda las copias fuera del VPS (en otro servidor o en almacenamiento de objetos): una copia en el mismo disco no te protege de la pérdida del servidor.

Solución de problemas

Un contenedor se reinicia una y otra vez. Revisa sus últimas líneas de log con docker compose logs --tail 50 mc-survival. Las causas más comunes son EULA sin aceptar, un heap (MEMORY) igual o mayor que mem_limit, o falta de espacio en disco.

Bind for 0.0.0.0:25565 failed: port is already allocated. Otro contenedor o proceso usa ese puerto en el host. Localízalo con sudo ss -tulpn | grep 25565 y cambia el puerto del host en compose.yaml.

Valheim no aparece en la lista pública. El registro en la lista de servidores puede tardar varios minutos tras el primer arranque. Mientras tanto, conéctate directamente con your_server_ip:2456 y confirma en docker compose logs valheim que el servidor ha terminado de cargar.

Conclusión

Tienes tres servidores de juegos aislados en contenedores dentro de un mismo VPS, cada uno con sus puertos, sus datos y límites de CPU y memoria que protegen a los demás. A partir de aquí, automatiza las copias con un temporizador de systemd o cron, protege los puertos del juego con reglas de rate limiting y revisa docker stats durante las horas punta para ajustar los límites antes de añadir más servidores.