Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Luanti containers, part 1: Comparing docker-compose and podman-compose rootful

I currently use Docker to run my Luanti game server and related services. But because I use RHEL derivatives (Rocky Linux, primarily), I wanted to see how the podman tech would work. Here's first post in a short series, explaining the differences in running Luanti in docker versus podman.

Docker-compose

I use docker-compose, so I define all the services in one file. It is very convenient for small scale deployments!

files/2026/listings/luanti-docker-compose.yml (Source)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File: /home/luanti/game-onyx/docker-compose.yml
# Author: bgstack15
# Startdate: 2026-02-20-6 08:42
# History:
#    2025
# this app in the container will not read the ~/.minetest/minetest.conf, particularly for mcl_keepInventory=true, so I had to modify ~/.minetest/games/mineclonia/minetest.conf
# Reference:
#    https://github.com/linuxserver/docker-luanti
#    https://github.com/minetest-mapserver/mapserver/blob/master/docker-compose.yml
#    https://github.com/minetest-mapserver/mapserver/blob/master/doc/install.md more useful
#    https://github.com/pandorabox-io/pandorabox.io/blob/master/docker-compose.yml#L45-L57
---
version: "3.5"
services:
  luanti:
    image: lscr.io/linuxserver/luanti:latest
    networks:
      - luanti
    environment:
      - PUID=1009
      - PGID=1009
      - TZ=Etc/UTC
      - "CLI_ARGS=--gameid mineclonia --worldname world"
    volumes:
      - /home/luanti/game-onyx/:/config/.minetest
    ports:
      - 30070:30000/udp
    restart: unless-stopped
  mapserver:
    image: ghcr.io/minetest-mapserver/mapserver:latest
    restart: always
    networks:
      - luanti
    volumes:
      - /home/luanti/game-onyx/worlds/world:/minetest
    working_dir: "/minetest"
    ports:
      - 30071:8080/tcp
  ui:
    image: ghcr.io/minetest-go/mtui:latest
    restart: always
    environment:
      WORLD_DIR: "/world"
      LOGLEVEL: debug
      #COOKIE_DOMAIN: "www.example.com"
      #COOKIE_SECURE: "false"
      #COOKIE_PATH: "/games/luanti/namibia/ui"
      SERVER_NAME: "Onyx"
      #WASM_MINETEST_HOST: "minetest"
      API_KEY: "ExampleKeyGoesHere"
      #all features: "api,shell,luashell,minetest_config,docker,modmanagement,signup,chat,minetest_web"
      # enable features does not work. I had to be an admin from minetest.conf `name=<myname>` and then visit webpage and enable shell, luashell, chat
      ENABLE_FEATURES: "shell,luashell,chat"
    volumes:
      - "/home/luanti/game-onyx/worlds/world:/world"
      #- "postgres_socket:/var/run/postgresql"
    networks:
      - luanti
    ports:
      - 30072:8080/tcp
networks:
  luanti:
    name: luanti07
...

I use a third-party image, and not the official Luanti image. The only reason is I found it first on the world wide web. The Mineclonia client side mod does not need anything special in server-side, so any image will suffice.

The environment variables PUID and GUID are specific to this image of Luanti, based on the build team's consistency between all their images.

Even with SELinux enforcing on the docker host, the container doesn't seem to need special selinux tags on the volume mounts :z.

The restart: unless-stopped makes the docker daemon restart these even at reboot.

And, it's a little out of scope here, but the minetest.conf needs to set mapserver.url and mtui.url values to the container names of those other services.

Podman compose rootful

This is the experimental stage for me, and it took me a little while to get it working.

files/2026/listings/luanti-rootful-podman-compose.yml (Source)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File: /home/luanti/game-onyx/docker-compose.yml
# Author: bgstack15
# Startdate: 2026-02-20-6 08:42
# History:
#    2025
# this app in the container will not read the ~/.minetest/minetest.conf, particularly for mcl_keepInventory=true, so I had to modify ~/.minetest/games/mineclonia/minetest.conf
# Reference:
#    https://github.com/linuxserver/docker-luanti
#    https://github.com/minetest-mapserver/mapserver/blob/master/docker-compose.yml
#    https://github.com/minetest-mapserver/mapserver/blob/master/doc/install.md more useful
#    https://github.com/pandorabox-io/pandorabox.io/blob/master/docker-compose.yml#L45-L57
---
version: "3.5"
services:
  luanti:
    image: lscr.io/linuxserver/luanti:latest
    networks:
      - luanti
    environment:
      - PUID=1009
      - PGID=1009
      - TZ=Etc/UTC
      - "CLI_ARGS=--gameid mineclonia --worldname world"
    volumes:
      # lscr.io image needs ./main-config/minetest.conf
      - /home/luanti/game-onyx/:/config/.minetest/:z
    ports:
      - 30070:30000/udp
      - 30070:30000/tcp
    restart: unless-stopped
  mapserver:
    image: ghcr.io/minetest-mapserver/mapserver:latest
    restart: always
    networks:
      - luanti
    volumes:
      - /home/luanti/game-onyx/worlds/world:/minetest:z
    working_dir: "/minetest"
    ports:
      - 30071:8080/tcp
  ui:
    image: ghcr.io/minetest-go/mtui:latest
    restart: always
    environment:
      WORLD_DIR: "/world"
      LOGLEVEL: debug
      #COOKIE_DOMAIN: "www.example.com"
      #COOKIE_SECURE: "false"
      #COOKIE_PATH: "/games/luanti/namibia/ui"
      SERVER_NAME: "Onyx"
      #WASM_MINETEST_HOST: "minetest"
      API_KEY: "ExampleKeyGoesHere"
      #all features: "api,shell,luashell,minetest_config,docker,modmanagement,signup,chat,minetest_web"
      # enable features does not work. I had to be an admin from minetest.conf `name=<myname>` and then visit webpage and enable shell, luashell, chat
      ENABLE_FEATURES: "shell,luashell,chat"
    volumes:
      - "/home/luanti/game-onyx/worlds/world:/world:z"
      #- "postgres_socket:/var/run/postgresql"
    networks:
      - luanti
    ports:
      - 30072:8080/tcp
networks:
  luanti:
    name: luanti07
...

Of course, install podman and podman-compose.

sudo dnf install -y podman podman-compose
sudo mkdir -p /etc/containers/containers.conf.d
echo "compose_warning_logs=false" | sudo tee /etc/containers/containers.conf.d/60-warnings.conf
sudo groupadd --gid 1009 luanti
sudo useradd --gid 1009 --uid 1009 luanti # I have not set a password
sudo loginctl enable-linger 1009

For the user to work with podman, I had to enable linger. I'm not going to go into the plagued history of this, today. This is necessary for any future podman use by this user, including the upcoming blog posts.

I had to use rootful podman (sudo podman-compose up) because the lscr.io image does some chown operations at initialization, and do not work in rootless mode.

I ran into some selinux problems, or at least I think I did. It certainly didn't hurt me to use the :z selinux option. Lowercase Z means podman should relabel the file objects for multiple containers, but uppercase Z would mean a private, unshared label for just this one container.

Common

The reverse proxy and port forwarding is out of scope for this document.

Comments