itzg / docker-minecraft-server

Docker image that provides a Minecraft Server that will automatically download selected version at startup
https://docker-minecraft-server.readthedocs.io/
Apache License 2.0
8.91k stars 1.49k forks source link

Server does not resume from autopause when port is knocked #1969

Closed Metalcape closed 1 year ago

Metalcape commented 1 year ago

Describe the problem

When using the autopause function, the knockd process will sometimes terminate, preventing the server from resuming when a client knocks on port 25565 or 19132 (if using GeyserMC). As a workaround, manually starting another knockd instance inside the container with knockd -c /tmp/knockd-config.cfg -d -i eth0 fixes the problem without having to restart the container.

I tried inspecting knockd's logs and when it terminates it just says:

[2023-02-21 14:27] waiting for child processes...
[2023-02-21 14:27] shutting down

Unfortunately I cannot consistently reproduce this issue, I've only observed that it tends to happen when the server pauses after all clients have disconnected.

Container definition

services:
  web:
      image: itzg/rcon
      container_name: rcon-web
      environment:
        VIRTUAL_HOST: admin.mc.server.home.arpa
        VIRTUAL_PORT: 4326

        RWA_USERNAME: admin
        RWA_PASSWORD: admin
        RWA_ADMIN: "TRUE"
        # is referring to the hostname of 'mc' compose service below
        RWA_RCON_HOST: mc
        # needs to match the password configured for the container, which is 'minecraft' by default
        RWA_RCON_PASSWORD: minecraft
      expose:
        - 4326
      ports:
        - 4326:4326
        - 4327:4327
      networks:
        default:
          ipv4_address: 172.16.0.101
  mc:
    image: itzg/minecraft-server
    container_name: paper-mc
    environment:
      VIRTUAL_HOST: dynmap.mc.server.home.arpa
      VIRTUAL_PORT: 8123

      # System
      EULA: "true"
      ENABLE_RCON: "true"
      TYPE: "PAPER"
      CONSOLE: "false"
      VERSION: "latest"
      ONLINE_MODE: "true"
      STOP_SERVER_ANNOUNCE_DELAY: 180
      ENABLE_ROLLING_LOGS: "true"
      TZ: "Europe/Rome"
      OVERRIDE_SERVER_PROPERTIES: "true"

      DEBUG: "true"
      AUTOPAUSE_TIMEOUT_INIT: 600
      AUTOPAUSE_TIMEOUT_EST: 600

      SPAWN_PROTECTION: 0
      ENABLE_WHITELIST: "true"
      ENFORCE_WHITELIST: "true"
      ENFORCE_SECURE_PROFILE: "false"

      # Performance
      VIEW_DISTANCE: 10
      SIMULATION_DISTANCE: 4
      MEMORY: "3G"
      MAX_PLAYERS: 20
      USE_AIKAR_FLAGS: "true"
      ENABLE_AUTOPAUSE: "true"
      MAX_TICK_TIME: -1
      JVM_DD_OPTS: "disable.watchdog:true"

      # Spiget plugins: No Chat Reports, PlaceholderAPI, Simple Tpa, MOTD, LuckPerms, One Player Sleep, UltimateHomes
      SPIGET_RESOURCES: "102990,6245,64270,8390,28140,31585,64210"

      # Manual plugins: Dynmap, Geyser, Floodgate, TAB, WorldEdit, WorldGuard
      MODS: >-
        https://dynmap.us/builds/dynmap/Dynmap-3.5-beta-2-spigot.jar,
        https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/lastSuccessfulBuild/artifact/bootstrap/spigot/build/libs/Geyser-Spigot.jar,
        https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/lastSuccessfulBuild/artifact/spigot/build/libs/floodgate-spigot.jar,
        https://github.com/NEZNAMY/TAB/releases/download/3.2.5/TAB.v3.2.5.jar,
        https://dev.bukkit.org/projects/worldedit/files/4162203/download,
        https://dev.bukkit.org/projects/worldguard/files/3903109/download

      # Datapacks: Craftable Bundles
      DATAPACKS: >-
        https://static.planetminecraft.com/files/resource_media/datapack/datapack-e2691.zip        

      # Gameplay
      MODE: "survival"
      DIFFICULTY: "normal"
      ENABLE_COMMAND_BLOCK: "false"
      ALLOW_FLIGHT: "false"
      SERVER_NAME: "Pomonte"
      MOTD: "§c§o§lPOMONTE"

    tty: true
    stdin_open: true
    expose:
      - 8123
    ports:
      - 25565:25565
      - 19132:19132/udp # Geyser
      - 8123:8123 # Dynmap
    volumes:
      - "paper-data:/data"
      - "paper-plugins:/plugins"
    restart: unless-stopped
    networks:
      default:
        ipv4_address: 172.16.0.102
  backups:
    image: itzg/mc-backup
    container_name: mc-backup
    environment:
      TZ: "Europe/Rome"
      PAUSE_IF_NO_PLAYERS: "true"
      BACKUP_INTERVAL: "24h"
      PRUNE_BACKUPS_DAYS: 7
      RCON_HOST: mc
      PRE_BACKUP_SCRIPT: |
        echo "Initiating backup from $$RCON_HOST to $$DEST_DIR"
      POST_BACKUP_SCRIPT: |
        echo "Backup from $$RCON_HOST to $$DEST_DIR finished"
    volumes:
    # mount the same volume used by server, but read-only
    - paper-data:/data:ro
    # use a host attached directory so that it in turn can be backed up
    # to external/cloud storage
    - backup:/backups
    networks:
      default:
        ipv4_address: 172.16.0.103

volumes:
  paper-data: 
    driver_opts:
      type: local
      o: bind
      device: /srv/minecraft
  paper-plugins: 
    driver_opts:
      type: local
      o: bind
      device: /srv/minecraft/plugins
  backup: 
    driver_opts:
      type: local
      o: bind
      device: /srv/media/minecraft/backup

networks:
  default:
    name: local-bridge
    external: true
Metalcape commented 1 year ago

After further inspection, it seems that knockd terminates with exit code 0, due to pcap_dispatch returning a negative value. https://github.com/jvinet/knock/blob/cb163f1509f57698c40a1bd8d1d6891af608a18b/src/knockd.c#L341

Metalcape commented 1 year ago

knockd crashes with error pcap: can't poll on packet socket: No child processes because it is triggering the resume script after every udp packet sent by bedrock clients, and so it quickly creates a lot of child processes while a bedrock client is connected, which eventually makes it crash.

To solve the problem we should find a way to trigger the script only after the first udp packet, or limit the rate at which knockd polls port 19132. Java clients don't cause this problem because they use TCP and the SYN flag in the config prevents this, but for UDP I don't think there is a way to tell the difference between the first packet and the others, unless we look at the application level protocol. Using something like iptables we could limit the rate of packets on port 19132, but that would likely cause lag for bedrock players. I also tried looking at knockd's man page but it doesn't seem to have any option to limit the rate of requests.