I was chatting with my friend Ray, and he had been working on a Valheim container to run in AWS Fargate to be a persistent place to play the game using CDK. He’s well and done with that project at this point, but I always like a challenge, so decided that I’d do something similar. As I haven’t played with containers much in awhile, and not Fargate at all beyone a tutorial, there has been a fair amount to learn and refresh.

Part 1: The container

I started with the container that Ray created as my base. I’ve made a few changes to it, since I wanted to use the world I’d been playing with on my server, and forked it to my repo. I will be making my updates there, and if they make sense, provide PRs back to Ray.

Overall, it’s a pretty simple container. It’s built on the official steamcmd image from Dockerhub.

FROM steamcmd/steamcmd
RUN steamcmd +login anonymous +force_install_dir /data +app_update 896660 +quit
COPY start_server.sh start_dedicated_server.sh
EXPOSE 2456-2457/udp
ENTRYPOINT ["/bin/bash", "./start_dedicated_server.sh" ]

It starts off by checking for updates, then moves the start_server.sh script into the container, with a different name to avoid being overwritten. Exposes the two UDP ports as needed, and starts the server.

I created a directory for my world with the config files and the worlds dir

> tree valheim_worldname

├── adminlist.txt
└── worlds
    ├── worldname.db
    ├── worldname.db.old
    ├── worldname.fwl
    └── worldname.fwl.old

Since I wanted to use my existing world, I created a volume for the world using docker volume create valheim_data and then populated it with the contents of my world.

  1. Inspect using docker volume inspect valheim_data
  2. Note the mountpoint indicated - for me it’s /var/lib/docker/volumes/valheim_data/_data
  3. cp -R valheim_data/* $mountpoint

As I was working with an existing world with a name, I wanted to include provisions for specifying the world name. I added:

if [ -z ${SERVER_WORLD:+x} ]; then

As an aside, I was curious about the test syntax inside the script. -z checks for the existence of a string, the :+x inside the parameter expansion is a substitution in the case the string exists. I think this will be done more cleanly by using :- in which case the absence gets substituted and is made for the case where it’s not existing - e.g. a default parameter. Adding to the backlog!

With the volume built and the script modified, I can now start the server. There’s still room to clean this up, but it works:

docker build -t valheim .
docker run -d -p 2456:2456/udp -p 2457:2457/udp -v valheim_data:/root/valheim -e SERVER_NAME="YOURSERVERNAME" -e SERVER_PASSWORD=YOURPASSWORD -e SERVER_WORLD="YOURWORLDNAME" valheim

Now you should be able to open up your Valheim, and Join a game on localhost. Good times!

Part 2: Building the infrastructure