Skip to content

Instantly share code, notes, and snippets.

@Tr4il
Last active November 19, 2023 16:02
Show Gist options
  • Save Tr4il/53aebdebaeedc6ff743ebeeee5672a4e to your computer and use it in GitHub Desktop.
Save Tr4il/53aebdebaeedc6ff743ebeeee5672a4e to your computer and use it in GitHub Desktop.

Intro

The other day, someone posted a little guide here for hosting a ATM8 server on a headless Linux machine. /u/AlexHailstone noted that Docker could work for this as well and would be nice, and I so happen to have ran my Minecraft servers in Docker containers for years now. So here is a little guide for you guys. This is not a Docker starter guide, you'll need to google around a bit for that if you're not familiar with Docker, but it shouldn't be too difficult.

(Just to cover my ass, I'm not responsible for any loss of (save)data or other risks you may open yourself up to by reading and using this little guide. Please make sure you understand what you're doing by running this. There shouldn't be any problems but if there are, I can't be held responsible!)

Let's get started!

Docker Containers

A Docker container can be started multiple ways, but two are the most used, for example with a docker run command:

docker run hello-world

is essentially saying: "Docker, run the image called hello-world (pull it from Docker Hub if you don't have it here) and tell me the exact output here in my terminal."

From there you can use all kinds of arguments to the command to customize the container to your liking.

You can also use a docker compose yml file, where you layout all your customisations and preferences regarding your containers in a file, that you then pass on to docker compose to start your containers (or container stack, as its also called). That is what I use and have used.

AllTheMods8 in a Docker Container

Now, /u/AlexHailstone mentioned a pre-configured docker image would be nice, but that's not quite what we'll be doing here. An image with ATM8 installed and ready to go would be quite big in size. But with my compose below, it will still be one command to start the server. I'll just start with the most important snippet of code, and continue to explain below that.

atm8-compose.yml:

version: "3.9"

networks:
  mc0:
    name: mc0
    enable_ipv6: false
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.90.0/24
    driver_opts:
      com.docker.network.bridge.name: mc0

services:

## Minecraft - ATM8

  atm8:
    container_name: atm8
    hostname: atm8
    image: itzg/minecraft-server:java19
    volumes:
    - /opt/atm8/modpacks:/modpacks:ro
    - /opt/atm8/data:/data
    - /mnt:/mnt
    environment:
    - EULA=TRUE
    - TYPE=AUTO_CURSEFORGE
    - CF_SLUG=all-the-mods-8
    - CF_FILE_ID=4372497
    - CF_API_KEY=$$INSERTYOUROWNHERE
    - TZ=$TZ
    - MEMORY=8G
    - ENABLE_RCON=true
    - RCON_PASSWORD=$PASSWORD
    - RCON_PORT=25575
    ports:
      - 25565:25565
      - 25575:25575
    restart: unless-stopped
    networks:
      mc0:
        ipv4_address: 192.168.90.10

Let's go through that so you know what this all means.

The first line defines the version of the file spec for compose we'll be maintaining, in this case 3.9. Afther that, we get the network block, where we define the docker network the container will be running in. This is not necessary, and you can remove this as long as you also remove the network blocks from the containers. I like to keep things tidy and define a network name, ip subnet and interface name (in this case both mc0.)

Then we get into the part where we define our container. My own compose file is bigger, with a lot of containers, so I insert a line here with the two hastags, so organise it all a bit. That makes that line just a comment for a user to read, the computer will skip that. Then there is the name of the "service" as these blocks are called, just atm8 in this case. We give it a proper container_name, and a hostname for the internal network. Then we get to the image we'll be using. There are plenty of Minecraft server images out there, but a Github user by the name of Geoff Bourne has made the most extensible and configurable container image I could find. You can find the page for that here and I recommend to go through the readme, to get a better understanding of what we're doing here. He has included all kinds of helpful scripts to help you run your server quick and easy. So, the image is itzg/minecraft-server. The part after the semicolon, in this case java19, is the tag or version of the image we want to use. The Java 19 version of the image is the latest and is fine for our uses, so that's what we'll use: itzg/minecraft-server:java19

Under volumes we configure the storage locations the container will be using for the server files, mods, configs and everything else. All my containers have their configuration and database files somewhere under /opt, so I created a directory there for atm8: /opt/atm8. The image uses two mountpoints, one for data and one for the modpack. The path in front of the semicolon is the path on the host, and the path after the semicolon is the path in the container. So, /opt/atm8/data gets mounted to /data in the container. Same goes for the modpacks directory. You can mount more host directories inside the container if you need them. I have a storage location under /mnt, so I mounted that to direct the backup files to there. (You'll need to configure that in the simplebackups config of course.)

Under environment you'll find any arguments and variables the server/container needs to know or have to operate properly. For example since Mojang/Microsoft requires you to agree to the End User License Agreement before you can start a server or play the game, the server makes sure you actually agree to the EULA before it lets you start it up. Therefore, you need to set the environment variable EULA to true.

To explain them all, here's a table:

Variable Value Explanation
EULA TRUE Agree to the EULA
TYPE AUTO_CURSEFORGE The type of server we will be running, eg. vanilla or a CF modpack
CF_SLUG all-the-mods-8 The modpack as titled in the CurseForge URL for it.
CF_FILE_ID 4372497 The numerical value of the modpack file you'd download on CF: https://www.curseforge.com/minecraft/modpacks/all-the-mods-8/download/4372497
TZ $TZ Timezone, eg. Europe/Berlin
MEMORY 8G The amount of memory to assign to the server, 8GB in this case.
ENABLE_RCON true Enabling the remote console
RCON_PASSWORD $PASSWORD The password for the remote console, set this yourself
RCON_PORT 25575 The port for the remote console

The numerical file number of the CF modpack file is set so that the server downloads and installs a specific version of the ATM8 modpack, in this case 1.0.10. If you don't specify this value, the server gets updated automatically, which I do not prefer. But you might. Simply remove that line if you like auto updates.

Next up the code block for the port mapping. This works kind of the same as with the volume/mountpoints. There's a port to use on the host, and where to map that port inside the container. There's only two in most cases. 25565 is the default port for Minecraft servers. This can be changed in server.properties after first start, or you can change it with an Environment Variable. See the Github page for the image for that. The other port, in this case 25575, is the port for the remote console. Make sure you set a password for this or remote the line, because otherwise people will be able to access the remote console without your permission! How RCON works can be found in the Github page linked above, or via Google.

The restart line sets the container up in such a way that it will always automatically restart in case of failure or crash, unless you stop the container manually.

Finally, we have a network code block, mapping it to network mc0 with IP 192.168.90.10

Now with this snippet saved to atm8-compose.yml in the /opt/atm8 directory, you should be ready to go. If you've got Docker up and running, you can run it as follows:

docker compose -f /opt/atm8/atm8-compose.yml up -d

This essentially says: "Docker, use your compose extension with the file at /opt/atm8/atm8-compose.yml to create and run the containers in the file, as daemons." Your server should be starting now. You can check the logs in the data directory, or with docker logs atm8. To stop the container in order to change a config or add a mod for example, you'd use docker stop atm8 and then docker start atm8 to start it again. Use docker kill atm8 if the server does not respond to normal commands/requests, and use docker restart atm8 to restart the server.

That should be it for just running a ATM8 server. I included the whole .yml file in this gist, you should be able to find it below and get started! If you're having troubles with anything just comment below or on the reddit post and I'll see what I can do. I am a busy bee though, so it might take a while.

version: "3.9"
networks:
mc0:
name: mc0
enable_ipv6: false
driver: bridge
ipam:
config:
- subnet: 192.168.90.0/24
driver_opts:
com.docker.network.bridge.name: mc0
services:
## Minecraft - ATM8
atm8:
container_name: atm8
hostname: atm8
image: itzg/minecraft-server:java19
volumes:
- /opt/atm8/modpacks:/modpacks:ro
- /opt/atm8/data:/data
- /mnt:/mnt
environment:
- EULA=TRUE
- TYPE=AUTO_CURSEFORGE
- CF_SLUG=all-the-mods-8
- CF_FILE_ID=4372497
- CF_API_KEY=$$INSERTYOUROWNHERE
- TZ=$TZ
- MEMORY=8G
- ENABLE_RCON=true
- RCON_PASSWORD=$PASSWORD
- RCON_PORT=25575
ports:
- 25565:25565
- 25575:25575
restart: unless-stopped
networks:
mc0:
ipv4_address: 192.168.90.10

Now, personally I also run a dynmap for my server so that everyone can see what the world looks like. I included an extended version of the compose file below with dynmap running in a separate container and using a mariadb/mysql server for storing its database, and the nginx config that goes with it. This is advanced stuff, but just in case someone has been trying to figure this stuff out and is helped with this, see the files below to see what I did to make it work. Keep in mind you'll need to configure dynmap to use the mysql/mariadb server. Dynmap would be visible on port 80 if you use the compose below. Remember to also use the DynmapBlockscan module once to generate the dynmap textures for your modded blocks. You only need to do that once, so remove the mod after doing that, and copy the generated textures into the parent directory. (This is all explained on the Dynmap wiki as well) Since this is quite a resource intensive task, it might be necessary to the set the max ticktime in the server.properties to -1 temporarily. My server would crash if I didn't do that first. You can change it back to default after generating the textures.

version: "3.9"
networks:
mc0:
name: mc0
enable_ipv6: false
driver: bridge
ipam:
config:
- subnet: 192.168.90.0/24
driver_opts:
com.docker.network.bridge.name: mc0
services:
## Minecraft - ATM8
atm8:
container_name: atm8
hostname: atm8
image: itzg/minecraft-server:java19
volumes:
- /opt/atm8/modpacks:/modpacks:ro
- /opt/atm8/data:/data
- /mnt:/mnt
environment:
- EULA=TRUE
- TYPE=AUTO_CURSEFORGE
- CF_SLUG=all-the-mods-8
- CF_FILE_ID=4372497
- CF_API_KEY=$$INSERTYOUROWNHERE
- TZ=$TZ
- MEMORY=8G
- ENABLE_RCON=true
- RCON_PASSWORD=$PASSWORD
- RCON_PORT=25575
ports:
- 25565:25565
- 25575:25575
restart: unless-stopped
networks:
mc0:
ipv4_address: 192.168.90.10
## Dynmap + Frontend
dynmap:
container_name: dynmap
hostname: dynmap
image: trafex/php-nginx
depends_on:
- mariadb
- atm8
volumes:
- /opt/atm8/data/dynmap/frontend/nginx-server.conf:/etc/nginx/conf.d/server.conf
- /opt/atm8/data/dynmap/web:/content/web
environment:
- TZ=$TZ
ports:
- 80:80
restart: unless-stopped
networks:
mc0:
ipv4_address: 192.168.90.11
## OPTIONAL
mariadb:
hostname: mariadb
container_name: mariadb
restart: unless-stopped
image: mariadb:10.7
security_opt:
- seccomp:unconfined
- apparmor:unconfined
command: mysqld --innodb-buffer-pool-size=128M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120
## Never store database files on an unreliable device such as a USB flash drive, an SD card, or a shared network folder:
volumes:
- "/opt/mariadb:/var/lib/mysql" # DO NOT REMOVE
environment:
MARIADB_AUTO_UPGRADE: "1"
MARIADB_INITDB_SKIP_TZINFO: "1"
MARIADB_ROOT_PASSWORD: "$MYSQL_ROOT_PW"
ports:
- "127.0.0.1:3307:3306"
networks:
mc0:
ipv4_address: 192.168.90.12
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /content/web;
index index.php index.html index.htm;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
location ~ \.php$ {
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
@BramvdVaart
Copy link

Hey, I am trying to use this guide to run an ATM 8 server with the latest build, but when I do I get this error. I am pretty new to docker and how all this works, so any help would be appreciated. [mc-image-helper] 18:52:56.461 ERROR : Invalid parameter provided for 'install-curseforge' command: API key is not set. Obtain an API key from https://console.curseforge.com/ and set the environment variable CF_API_KEY

Create an API key in the provided link and add ->
CF_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx
to your environments. Keep in mind that if the key contains $ it will be seen as a variable, so double $$ to signal it is an actual dollar sign and not a variable. Also u might need to add ->
services:
under version. I had to at least.

Hope this helped you, I finally got my server running today (new to linux, docker and this image)

also thanks for the great guide @Tr4il , helped a lot!

@KongGal
Copy link

KongGal commented Jul 9, 2023

Add a tip section.
Add tip to create a perm alias for docker
nano / vi / vim ~/.bashrc
add to the bottom of the file
#My custom aliases
alias dc='docker-compose -f /opt/atm8/atm8-compose.yml'
save the file and run
source ~/.bashrc

you can now use dc to run docker compose command anywhere such as dc ps, dc stop, dc restart, dc build, dc create, dc start, dc ps, dc logs

you should also update your command to docker logs -f --tail 25 atm8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment