Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
312 lines (275 loc) · 11.1 KB
/
Copy pathDockerfile
File metadata and controls
312 lines (275 loc) · 11.1 KB
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# syntax=docker/dockerfile:1
# The Steam client is still 32-bit, so use its Ubuntu image as the source for
# steamcmd and the i386 libraries it needs.
FROM --platform=linux/amd64 steamcmd/steamcmd:ubuntu-22 AS builder_amd64
# Install prerequisites to download steamcmd
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl tar \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /root/installer
# Download and unpack installer
RUN curl --fail --silent --show-error --location \
https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz \
| tar --extract --gzip --verbose
# Pin the runtime distribution. Tracking ubuntu:latest allowed Ubuntu 26.04 to
# land without its matching .NET native dependencies and broke every new image.
FROM ubuntu:24.04 AS runtime-base
ARG TARGETARCH
# Runtime releases are installed into persistent storage on first startup.
ARG TMOD_CHANNEL=stable
ENV TMOD_AUTO_UPDATE="1"
ENV TMOD_UPDATE_MIN_FREE_MB="1024"
ENV TMOD_UPDATE_TEST_TIMEOUT="600"
# Published images use an unprivileged runtime identity. Custom local builds can
# select another fixed identity. The root-only initializer repairs mounted data
# ownership before dropping permanently to this identity.
ARG TMOD_UID=1000
ARG TMOD_GID=1000
# The shutdown message is broadcast to the game chat when the container was stopped from the host.
ENV TMOD_SHUTDOWN_MESSAGE="Server is shutting down NOW!"
ENV TMOD_SHUTDOWN_DELAY="3"
ENV TMOD_RESTART_INTERVAL="0"
ENV TMOD_RESTART_MODE="disabled"
ENV TMOD_RESTART_DAYS="7"
ENV TMOD_RESTART_WEEKDAY="sunday"
ENV TMOD_RESTART_MONTHDAY="1"
ENV TMOD_RESTART_TIME="04:00"
ENV TMOD_RESTART_TIMEZONE="UTC"
ENV TMOD_RESTART_DELAY="60"
ENV TMOD_RESTART_COUNTDOWN="300,60,10"
ENV TMOD_RESTART_MESSAGE="Scheduled server restart soon. Please prepare to disconnect."
ENV TMOD_SHUTDOWN_TIMEOUT="90"
# The autosave feature will save the world periodically. The interval is in minutes.
ENV TMOD_AUTOSAVE_INTERVAL="10"
ENV TMOD_AUTOSAVE_MESSAGE="Scheduled world save starting."
# Docker console verbosity. Complete raw output remains in the persistent log.
ENV TMOD_LOG_LEVEL="normal"
ENV TMOD_CRASH_LOG_LINES="200"
ENV TMOD_LOG_RETENTION_DAYS="30"
ENV TMOD_LOG_HISTORY_MAX_MB="512"
ENV TMOD_LOG_ROTATE_MB="64"
ENV TMOD_BACKUP_MODE="interval"
ENV TMOD_BACKUP_DAYS="7"
ENV TMOD_BACKUP_WEEKDAY="sunday"
ENV TMOD_BACKUP_MONTHDAY="1"
ENV TMOD_BACKUP_TIME="03:00"
ENV TMOD_BACKUP_TIMEZONE="UTC"
# Workshop mods to keep current and enable when the server starts.
# Example format: 2824688072,2824688266,2835214226
ENV TMOD_MODS=""
# Retry transient Steam Workshop failures before aborting startup.
ENV TMOD_DOWNLOAD_RETRIES="3"
ENV TMOD_DOWNLOAD_RETRY_DELAY="10"
ENV TMOD_MOD_OFFLINE_POLICY="use-cache"
ENV TMOD_COLLECTION_MAX_ITEMS="1000"
# If you want to specify your own config, set the following to "Yes".
ENV TMOD_USECONFIGFILE="No"
ENV TMOD_PASS_FILE=""
#--------- CONFIG SECTION --------- #
# The following environment variables will configure common settings for the tModLoader server.
# motd
ENV TMOD_MOTD="A tModLoader server powered by Docker!"
# password
ENV TMOD_PASS="docker"
# maxplayers
ENV TMOD_MAXPLAYERS="8"
# worldname
ENV TMOD_WORLDNAME="Docker"
# autocreate
ENV TMOD_WORLDSIZE="3"
ENV TMOD_WORLDEVIL="random"
# seed
ENV TMOD_WORLDSEED="Docker"
# difficulty
ENV TMOD_DIFFICULTY="1"
# secure
ENV TMOD_SECURE="0"
# language
ENV TMOD_LANGUAGE="en-US"
# npcstream
ENV TMOD_NPCSTREAM="60"
# upnp
ENV TMOD_UPNP="0"
# priority
ENV TMOD_PRIORITY="1"
# port
ENV TMOD_PORT="7777"
# JOURNEY MODE POWER PERMISSIONS
# journeypermission_time_setfrozen
ENV TMOD_JOURNEY_SETFROZEN="0"
# journeypermission_time_setdawn
ENV TMOD_JOURNEY_SETDAWN="0"
# journeypermission_time_setnoon
ENV TMOD_JOURNEY_SETNOON="0"
# journeypermission_time_setdusk
ENV TMOD_JOURNEY_SETDUSK="0"
# journeypermission_time_setmidnight
ENV TMOD_JOURNEY_SETMIDNIGHT="0"
# journeypermission_godmode
ENV TMOD_JOURNEY_GODMODE="0"
# journeypermission_wind_setstrength
ENV TMOD_JOURNEY_WIND_STRENGTH="0"
# journeypermission_rain_setstrength
ENV TMOD_JOURNEY_RAIN_STRENGTH="0"
# journeypermission_time_setspeed
ENV TMOD_JOURNEY_TIME_SPEED="0"
# journeypermission_rain_setfrozen
ENV TMOD_JOURNEY_RAIN_FROZEN="0"
# journeypermission_wind_setfrozen
ENV TMOD_JOURNEY_WIND_FROZEN="0"
# journeypermission_increaseplacementrange
ENV TMOD_JOURNEY_PLACEMENT_RANGE="0"
# journeypermission_setdifficulty
ENV TMOD_JOURNEY_SET_DIFFICULTY="0"
# journeypermission_biomespread_setfrozen
ENV TMOD_JOURNEY_BIOME_SPREAD="0"
# journeypermission_setspawnrate
ENV TMOD_JOURNEY_SPAWN_RATE="0"
# Loading a custom configuration file expects a Terraria server config mounted
# at /terraria-server/customconfig.txt. Set this to "Yes" to use that file.
# ENV TMOD_USECONFIGFILE="No"
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
jq \
libc6 \
libgcc-s1 \
libgssapi-krb5-2 \
libicu74 \
libsdl2-2.0-0 \
libssl3 \
libstdc++6 \
locales \
python3 \
python3-waitress \
python3-argon2 \
python3-cryptography \
python3-yaml \
argon2 \
tini \
tzdata \
unzip \
util-linux \
wget \
zlib1g \
&& case "$TARGETARCH" in \
amd64|arm64) ;; \
*) echo "Unsupported architecture: $TARGETARCH (use amd64 or arm64)" >&2; exit 1 ;; \
esac \
&& locale-gen en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*
ENV LANG="en_US.UTF-8"
ENV LC_ALL="en_US.UTF-8"
RUN case "$TMOD_UID" in ''|*[!0-9]*|0) echo "TMOD_UID must be a positive integer." >&2; exit 1 ;; esac \
&& case "$TMOD_GID" in ''|*[!0-9]*|0) echo "TMOD_GID must be a positive integer." >&2; exit 1 ;; esac \
&& existing_user="$(getent passwd "$TMOD_UID" | cut -d: -f1)" \
&& existing_group="$(getent group "$TMOD_GID" | cut -d: -f1)" \
&& if [ "$existing_user" = ubuntu ] && [ "$existing_group" = ubuntu ]; then \
groupmod --new-name tml ubuntu; \
usermod --login tml --comment 'tModLoader runtime' --home /home/tml --move-home ubuntu; \
elif [ -n "$existing_user" ] || [ -n "$existing_group" ]; then \
echo "TMOD_UID or TMOD_GID is already assigned in the base image." >&2; \
exit 1; \
else \
groupadd --gid "$TMOD_GID" tml; \
useradd --no-log-init --uid "$TMOD_UID" --gid "$TMOD_GID" \
--create-home --home-dir /home/tml --shell /bin/bash tml; \
fi \
&& install -d -m 0755 -o tml -g tml \
/home/tml/.steam \
/data \
/backups \
/data/steamMods \
/data/tModLoader \
/data/tModLoader/Logs \
/data/tModLoader/ModConfigs \
/data/tModLoader/Mods \
/data/tModLoader/Worlds \
/terraria-server
ENV HOME="/home/tml"
ENV USER="tml"
USER tml:tml
EXPOSE 7777
WORKDIR /terraria-server
FROM runtime-base AS runtime-amd64
# Valve's downloader is kept on the existing AMD64 platform only.
COPY --from=builder_amd64 /root/installer/ /opt/steamcmd-seed/
COPY --from=builder_amd64 /lib/i386-linux-gnu/ /opt/steam-runtime/lib/
COPY --from=builder_amd64 /root/installer/linux32/libstdc++.so.6 /opt/steam-runtime/lib/
USER root:root
RUN ln -s /opt/steam-runtime/lib/ld-linux.so.2 /lib/ld-linux.so.2
COPY --chown=root:root --chmod=0755 steamcmd-wrapper.sh /usr/bin/steamcmd
USER tml:tml
ENV TMOD_WORKSHOP_BACKEND="steamcmd"
RUN steamcmd +login anonymous +quit
FROM runtime-base AS runtime-arm64
# Native .NET downloader avoids x86 SteamCMD and any host emulation requirement.
ARG DEPOTDOWNLOADER_VERSION=3.4.0
USER root:root
RUN curl --fail --silent --show-error --location --retry 5 \
"https://github.com/SteamRE/DepotDownloader/releases/download/DepotDownloader_${DEPOTDOWNLOADER_VERSION}/DepotDownloader-linux-arm64.zip" \
--output /tmp/depotdownloader.zip \
&& unzip -q /tmp/depotdownloader.zip -d /opt/depotdownloader \
&& chmod 755 /opt/depotdownloader/DepotDownloader \
&& ln -s /opt/depotdownloader/DepotDownloader /usr/local/bin/depotdownloader \
&& rm /tmp/depotdownloader.zip
USER tml:tml
ENV TMOD_WORKSHOP_BACKEND="depotdownloader"
RUN depotdownloader --version
FROM runtime-${TARGETARCH} AS runtime
COPY --chown=tml:tml entrypoint.sh .
COPY --chown=tml:tml run-server.sh .
COPY --chown=tml:tml create_world.py .
COPY --chown=tml:tml console_tee.py .
COPY --chown=tml:tml filter_client_mods.py .
COPY --chown=tml:tml log-filter.sh .
COPY --chown=tml:tml manage-mods.sh workshop_download.py ./
COPY --chown=root:root --chmod=0755 inject.sh /usr/local/bin/inject
COPY --chown=root:root --chmod=0755 healthcheck.sh /usr/local/bin/healthcheck
COPY --chown=tml:tml autosave.sh .
COPY --chown=tml:tml prepare-config.sh .
COPY --chown=root:root backup.py admin_backup_details.py ./
COPY --chown=root:root --chmod=0755 container-backup.py /usr/local/bin/tmod-backup
COPY --chown=tml:tml VERSION .
COPY --chown=tml:tml admin_settings.py admin_metrics.py admin_workshop.py admin_server.py ./
COPY --chown=tml:tml admin_schema.py admin_auth.py admin_access.py admin_restart.py admin_backup_schedule.py admin_logs.py ./
COPY --chown=tml:tml admin_recovery.py ./
COPY --chown=tml:tml admin_players.py ./
COPY --chown=tml:tml admin_player_history.py ./
COPY --chown=tml:tml character_bridge.py ./
COPY --chown=tml:tml server-mod ./server-mod
COPY --chown=tml:tml admin_worlds.py admin_world_metadata.py admin_world_time.py admin_journey.py ./
COPY --chown=tml:tml admin_modconfigs.py ./
COPY --chown=tml:tml admin_updates.py runtime_updates.py ./
COPY --chown=tml:tml admin_profiles.py admin_playthroughs.py ./
COPY --chown=tml:tml web ./web
COPY --chown=root:root --chmod=0755 container-init.sh /usr/local/bin/tmod-init
ENV TMOD_BACKUP_INTERVAL="0"
ENV TMOD_BACKUP_KEEP="7"
ENV TMOD_BACKUP_MIN_FREE_MB="1024"
ENV TMOD_WEB_ENABLED="1"
ENV TMOD_WEB_PORT="8080"
ENV TMOD_WEB_ORIGIN=""
ENV TMOD_WEB_TRUSTED_PROXY=""
ENV TMOD_WEB_TOKEN_FILE=""
ENV TMOD_WORKSHOP_KEY_FILE=""
USER root
RUN sed -i 's/\r$//' /usr/local/bin/tmod-backup
USER tml
RUN /usr/local/bin/tmod-backup --help > /dev/null
RUN chmod 755 ./entrypoint.sh ./run-server.sh ./log-filter.sh ./manage-mods.sh ./autosave.sh ./prepare-config.sh
RUN python3 -c 'import json,sys; from pathlib import Path; print(json.dumps({"container_version":Path("VERSION").read_text().strip(),"update_channel":sys.argv[1]}))' "$TMOD_CHANNEL" > backup-runtime.json
RUN sha256sum VERSION entrypoint.sh run-server.sh create_world.py backup.py admin_backup_details.py backup-runtime.json \
/usr/local/bin/tmod-backup /usr/local/bin/tmod-init \
| sha256sum | cut -d ' ' -f 1 > backup-build-id
# Startup needs root only long enough to repair /data and /backups. tmod-init
# then changes identity and replaces itself with non-root tini and the existing
# entrypoint, leaving no root-owned wrapper process behind.
USER root:root
# WebUI setup is healthy while waiting for credentials; after setup, require the game.
# Headless deployments can override the grace period for initial runtime downloads.
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 CMD ["healthcheck", "--container"]
STOPSIGNAL SIGTERM
ENTRYPOINT ["/usr/local/bin/tmod-init", "/usr/bin/tini", "--", "./entrypoint.sh"]