diff --git a/tmserver/GameData/Config/config.xml b/tmserver/GameData/Config/config.xml
new file mode 100644
index 0000000..d3729e1
--- /dev/null
+++ b/tmserver/GameData/Config/config.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+ SuperAdmin
+ @SERVER_SA_PASSWORD@
+
+
+ Admin
+ @SERVER_ADM_PASSWORD@
+
+
+ User
+ User
+
+
+
+
+ @SERVER_LOGIN@
+ @SERVER_LOGIN_PASSWORD@
+ @VALIDATION_KEY@
+
+
+
+ @SERVER_NAME@
+ @SERVER_COMMENT@
+ @HIDE_SERVER@
+
+ @MAX_PLAYERS@
+ @SERVER_PASSWORD@
+
+ 32
+
+
+ forced
+ 0
+ 50000
+
+ True
+ True
+
+ 60000
+ 0.5
+
+
+
+
+
+ True
+ False
+ False
+
+
+ 0
+
+ False
+
+
+
+ 512
+ 8192
+
+
+ $SERVER_PORT
+ $SERVER_P2P_PORT
+ 0
+
+
+
+ 600
+
+ 5000
+ True
+
+
+
+
+
+ stadium
+
+ False
+
+
+
+
+
+ False
+
+
+
+
diff --git a/tmserver/GameData/Tracks/MatchSettings/playlist.xml b/tmserver/GameData/Tracks/MatchSettings/playlist.xml
new file mode 100644
index 0000000..39dbf67
--- /dev/null
+++ b/tmserver/GameData/Tracks/MatchSettings/playlist.xml
@@ -0,0 +1,39 @@
+
+
+
+ @GAMEMODE@
+ @CHATTIME@
+ @FINISHTIMEOUT@
+ 0
+ @DISABLERESPAWN@
+ 0
+ @ROUNDS_POINTSLIMIT@
+ 0
+ 0
+ 5
+ @TEAM_POINTSLIMIT@
+ @TEAM_MAXPOINTS@
+ 0
+ 5
+ @TIMEATTACK_LIMIT@
+ 0
+ @LAPS_NBLAPS@
+ @LAPS_TIMELIMIT@
+ @CUP_POINTSLIMIT@
+ @CUP_ROUNDSPERCHALLENGE@
+ @CUP_NBWINNERS@
+ @CUP_WARMUPDURATION@
+
+
+
+ 1
+ 1
+ 0
+ 0
+ 7
+ 0
+ 0
+
+
+ 0
+
diff --git a/tmserver/bin/eval_env.sh b/tmserver/bin/eval_env.sh
new file mode 100755
index 0000000..f850901
--- /dev/null
+++ b/tmserver/bin/eval_env.sh
@@ -0,0 +1,72 @@
+#!/command/with-contenv bash
+
+config=( )
+playlist=( )
+
+# Mandatory
+SERVER_SA_PASSWORD=${SERVER_SA_PASSWORD:?ERROR | SuperAdminPassword needs to be set. Generate with pwgen if needed.} && \
+ config+=( "SERVER_SA_PASSWORD" )
+SERVER_ADM_PASSWORD=${SERVER_ADM_PASSWORD:?ERROR | AdminPassword needs to be set. Generate with pwgen if needed.} && \
+ config+=( "SERVER_ADM_PASSWORD" )
+SERVER_LOGIN=${SERVER_LOGIN?:ERROR | ServerLogin is missing. Server cannot start.} && \
+ config+=( "SERVER_LOGIN" )
+SERVER_LOGIN_PASSWORD=${SERVER_LOGIN_PASSWORD?:ERROR | ServerLoginPassword is missing. Server cannot start.} && \
+ config+=( "SERVER_LOGIN_PASSWORD" )
+
+# Optional
+SERVER_PORT=${SERVER_PORT:-2350} && config+=( "SERVER_PORT" )
+echo "INFO | SERVER_PORT: ${SERVER_PORT}"
+SERVER_P2P_PORT=${SERVER_P2P_PORT:-3450} && config+=( "SERVER_P2P_PORT" )
+echo "INFO | SERVER_P2P_PORT: ${SERVER_P2P_PORT}"
+SERVER_NAME=${SERVER_NAME:-Trackmania Server} && config+=( "SERVER_NAME" )
+echo "INFO | SERVER_NAME: ${SERVER_NAME}"
+SERVER_COMMENT=${SERVER_COMMENT:-This is a Trackmania Server} && config+=( "SERVER_COMMENT" )
+echo "INFO | SERVER_COMMENT: ${SERVER_COMMENT}"
+SERVER_PASSWORD=${SERVER_PASSWORD} && config+=( "SERVER_PASSWORD" )
+echo "INFO | SERVER_PASSWORD: ${SERVER_PASSWORD}"
+HIDE_SERVER=${HIDE_SERVER:-0} && config+=( "HIDE_SERVER" )
+echo "INFO | HIDE_SERVER: ${HIDE_SERVER}"
+MAX_PLAYERS=${MAX_PLAYERS:-32} && config+=( "MAX_PLAYERS" )
+echo "INFO | MAX_PLAYERS: ${MAX_PLAYERS}"
+
+# Game Config
+GAMEMODE=${GAMEMODE:-1} && playlist+=( "GAMEMODE" )
+echo "INFO | GAMEMODE: ${GAMEMODE} | 1 = TimeAttack"
+CHATTIME=${CHATTIME:-10000} && playlist+=( "CHATTIME" )
+echo "INFO | CHATTTIME: ${CHATTIME} ms"
+FINISHTIMEOUT=${FINISHTIMEOUT:-1} && playlist+=( "FINISHTIMEOUT" )
+echo "INFO | FINISHTIMEOUT: ${FINISHTIMEOUT}"
+DISABLERESPAWN=${DISABLERESPAWN:-0} && playlist+=( "DISABLERESPAWN" )
+echo "INFO | DISABLERESPAWN: ${DISABLERESPAWN}"
+ROUNDS_POINTSLIMIT=${ROUNDS_POINTSLIMIT:-30} && playlist+=( "ROUNDS_POINTSLIMIT" )
+echo "INFO | ROUNDS_POINTSLIMIT: ${ROUNDS_POINTSLIMIT}"
+TIMEATTACK_LIMIT=${TIMEATTACK_LIMIT:-180000} && playlist+=( "TIMEATTACK_LIMIT" )
+echo "INFO | TIMEATTACK_LIMIT: ${TIMEATTACK_LIMIT} ms"
+TEAM_POINTSLIMIT=${TEAM_POINTSLIMIT:-50} && playlist+=( "TEAM_POINTSLIMIT" )
+echo "INFO | TEAM_POINTSLIMIT: ${TEAM_POINTSLIMIT}"
+TEAM_MAXPOINTS=${TEAM_MAXPOINTS:-6} && playlist+=( "TEAM_MAXPOINTS" )
+echo "INFO | TEAM_MAXPOINTS: ${TEAM_MAXPOINTS}"
+LAPS_NBLAPS=${LAPS_NBLAPS:-5} && playlist+=( "LAPS_NBLAPS" )
+echo "INFO | LAPS_NBLAPS: ${LAPS_NBLAPS}"
+LAPS_TIMELIMIT=${LAPS_TIMELIMIT:-0} && playlist+=( "LAPS_TIMELIMIT" )
+echo "INFO | LAPS_TIMELIMIT: ${LAPS_TIMELIMIT}"
+CUP_POINTSLIMIT=${CUP_POINTSLIMIT:-100} && playlist+=( "CUP_POINTSLIMIT" )
+echo "INFO | CUP_POINTSLIMIT: ${CUP_POINTSLIMIT}"
+CUP_ROUNDSPERCHALLENGE=${CUP_ROUNDSPERCHALLENGE:-5} && playlist+=( "CUP_ROUNDSPERCHALLENGE" )
+echo "INFO | CUP_ROUNDSPERCHALLENGE: ${CUP_ROUNDSPERCHALLENGE}"
+CUP_NBWINNERS=${CUP_NBWINNERS:-3} && playlist+=( "CUP_NBWINNERS" )
+echo "INFO | CUP_NBWINNERS: ${CUP_NBWINNERS}"
+CUP_WARMUPDURATION=${CUP_WARMUPDURATION:-2} && playlist+=( "CUP_WARMUPDURATION" )
+echo "INFO | CUP_WARMUPDURATION: ${CUP_WARMUPDURATION}"
+
+# Parse config.xml
+for idx in "${!config[@]}"; do
+ arg=${config[$idx]}
+ sed -i -e "s/@$arg@/${!arg}/g" GameData/Config/config.xml
+done
+
+# Parse playlist.xml
+for idx in "${!playlist[@]}"; do
+ arg=${playlist[$idx]}
+ sed -i -e "s/@$arg@/${!arg}/g" GameData/Tracks/MatchSettings/playlist.xml
+done
\ No newline at end of file
diff --git a/tmserver/bin/eval_playlist.sh b/tmserver/bin/eval_playlist.sh
new file mode 100755
index 0000000..181eff6
--- /dev/null
+++ b/tmserver/bin/eval_playlist.sh
@@ -0,0 +1,20 @@
+#!/command/with-contenv bash
+
+echo "INFO | Parsing custom playlist..."
+
+CUSTOM_PLAYLIST=${CUSTOM_PLAYLIST:-playlist.txt}
+PLAYLIST_FILE='GameData/Tracks/MatchSettings/playlist.xml'
+
+if [[ -f "${CUSTOM_PLAYLIST}" ]]; then
+ count=1
+ while read l; do
+ xmlstarlet ed -L -s /playlist -t elem -n challenge $PLAYLIST_FILE
+ xmlstarlet ed -L -s "/playlist/challenge[${count}]" -t elem -n file -v "${l}" $PLAYLIST_FILE
+ count=$((count+1))
+ done < $CUSTOM_PLAYLIST
+else
+ xmlstarlet ed -L -s /playlist -t elem -n challenge $PLAYLIST_FILE
+ xmlstarlet ed -L -s "playlist/challenge[1]" -t elem -n file -v "Challenges/Nadeo/A01-Race.Challenge.Gbx" $PLAYLIST_FILE
+fi
+
+echo "INFO | Finished parsing playlist files."
diff --git a/tmserver/entrypoint.sh b/tmserver/entrypoint.sh
new file mode 100755
index 0000000..1d96ab2
--- /dev/null
+++ b/tmserver/entrypoint.sh
@@ -0,0 +1,15 @@
+#!/command/with-contenv bash
+
+set -e
+
+[[ "$(id -u)" == 0 ]] && s6-setuidgid trackmania "$0"
+
+cd /var/lib/tmserver
+
+# Parse config files
+./bin/eval_env.sh
+
+# Parse playlist files
+./bin/eval_playlist.sh
+
+exec "./TrackmaniaServer" "/nodaemon" "/internet" "/game_settings=MatchSettings/playlist.xml" "/dedicated_cfg=config.xml"