mirror of
				https://github.com/factoriotools/factorio-docker.git
				synced 2025-10-31 00:48:07 +01:00 
			
		
		
		
	feat: Add rootless Docker support
Implements #547 - Add support for rootless Docker images to avoid permission issues. Key changes: - Add Dockerfile.rootless that runs as UID 1000 by default - Create simplified entrypoint script without chown operations - Add build-rootless.py to build rootless variants with -rootless suffix - Document rootless usage in README-ROOTLESS.md - Update main README with rootless section The rootless images eliminate common permission problems by: - Running as non-root from the start (USER 1000:1000) - Avoiding recursive chown operations that can cause race conditions - Using open permissions (777) on directories during build - Not supporting PUID/PGID environment variables This provides a cleaner solution for rootless Docker users and those experiencing permission issues with volumes. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							
								
								
									
										136
									
								
								README-ROOTLESS.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								README-ROOTLESS.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
| # Rootless Docker Support | ||||
|  | ||||
| This document describes the rootless Docker images for Factorio, which are designed to work better with rootless Docker installations and avoid permission issues. | ||||
|  | ||||
| ## What is Rootless Docker? | ||||
|  | ||||
| Rootless Docker allows running the Docker daemon and containers as a non-root user, which improves security by eliminating the need for root privileges. However, it introduces complexity with UID/GID mapping that can cause permission issues with volumes. | ||||
|  | ||||
| ## Rootless Image Tags | ||||
|  | ||||
| For each regular Factorio image tag, there's a corresponding rootless tag with the `-rootless` suffix: | ||||
|  | ||||
| - `latest` → `latest-rootless` | ||||
| - `stable` → `stable-rootless` | ||||
| - `2.0.55` → `2.0.55-rootless` | ||||
| - etc. | ||||
|  | ||||
| ## Key Differences from Regular Images | ||||
|  | ||||
| 1. **No dynamic UID/GID mapping**: The rootless images run as UID 1000 by default and don't support PUID/PGID environment variables | ||||
| 2. **No runtime chown operations**: Eliminates the recursive chown that can cause race conditions | ||||
| 3. **Simplified permissions**: All directories are created with open permissions (777) during build | ||||
| 4. **USER directive**: The container runs as non-root from the start | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| ### Basic Usage | ||||
|  | ||||
| ```bash | ||||
| docker run -d \ | ||||
|   -p 34197:34197/udp \ | ||||
|   -p 27015:27015/tcp \ | ||||
|   -v /opt/factorio:/factorio \ | ||||
|   --name factorio \ | ||||
|   factoriotools/factorio:stable-rootless | ||||
| ``` | ||||
|  | ||||
| ### With Rootless Docker | ||||
|  | ||||
| If you're running rootless Docker, the container will work out of the box: | ||||
|  | ||||
| ```bash | ||||
| # As your regular user (not root) | ||||
| docker run -d \ | ||||
|   -p 34197:34197/udp \ | ||||
|   -p 27015:27015/tcp \ | ||||
|   -v ~/factorio:/factorio \ | ||||
|   --name factorio \ | ||||
|   factoriotools/factorio:stable-rootless | ||||
| ``` | ||||
|  | ||||
| ### With Regular Docker | ||||
|  | ||||
| If you're running regular Docker but want to avoid permission issues: | ||||
|  | ||||
| ```bash | ||||
| # Pre-create the volume directory with your user's permissions | ||||
| mkdir -p /opt/factorio | ||||
| sudo chown -R $(id -u):$(id -g) /opt/factorio | ||||
|  | ||||
| # Run the container | ||||
| docker run -d \ | ||||
|   --user $(id -u):$(id -g) \ | ||||
|   -p 34197:34197/udp \ | ||||
|   -p 27015:27015/tcp \ | ||||
|   -v /opt/factorio:/factorio \ | ||||
|   --name factorio \ | ||||
|   factoriotools/factorio:stable-rootless | ||||
| ``` | ||||
|  | ||||
| ## Environment Variables | ||||
|  | ||||
| All the same environment variables from the regular image are supported, except: | ||||
| - `PUID` - Not supported (container runs as UID 1000) | ||||
| - `PGID` - Not supported (container runs as GID 1000) | ||||
|  | ||||
| ## Migrating from Regular Images | ||||
|  | ||||
| If you're switching from a regular image to a rootless image: | ||||
|  | ||||
| 1. Stop your existing container | ||||
| 2. Fix permissions on your volume (one time only): | ||||
|    ```bash | ||||
|    sudo chown -R 1000:1000 /opt/factorio | ||||
|    # Or if you want to match your user: | ||||
|    sudo chown -R $(id -u):$(id -g) /opt/factorio | ||||
|    ``` | ||||
| 3. Start the new rootless container | ||||
|  | ||||
| ## Troubleshooting | ||||
|  | ||||
| ### Permission Denied Errors | ||||
|  | ||||
| If you get permission errors, ensure your volume directory is writable by UID 1000 or your user: | ||||
|  | ||||
| ```bash | ||||
| # Check current ownership | ||||
| ls -la /opt/factorio | ||||
|  | ||||
| # Fix ownership for UID 1000 (default) | ||||
| sudo chown -R 1000:1000 /opt/factorio | ||||
|  | ||||
| # Or fix for your current user | ||||
| sudo chown -R $(id -u):$(id -g) /opt/factorio | ||||
| ``` | ||||
|  | ||||
| ### Running as a Different User | ||||
|  | ||||
| If you need to run as a different UID, override it at runtime: | ||||
|  | ||||
| ```bash | ||||
| docker run -d \ | ||||
|   --user 2000:2000 \ | ||||
|   -v /opt/factorio:/factorio \ | ||||
|   factoriotools/factorio:stable-rootless | ||||
| ``` | ||||
|  | ||||
| ## Building Rootless Images | ||||
|  | ||||
| To build rootless images locally: | ||||
|  | ||||
| ```bash | ||||
| # Build for current architecture | ||||
| python3 build-rootless.py | ||||
|  | ||||
| # Build and push multi-arch images | ||||
| python3 build-rootless.py --multiarch --push-tags | ||||
| ``` | ||||
|  | ||||
| ## Why Use Rootless Images? | ||||
|  | ||||
| 1. **Avoid permission issues**: No more files with unexpected ownership | ||||
| 2. **Better security**: Runs as non-root by default | ||||
| 3. **Simpler**: No complex permission logic at startup | ||||
| 4. **Faster startup**: No recursive chown operations | ||||
| 5. **Rootless Docker compatible**: Works seamlessly with rootless Docker installations | ||||
							
								
								
									
										31
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								README.md
									
									
									
									
									
								
							| @@ -439,6 +439,37 @@ stream { | ||||
|  | ||||
| If your factorio host uses multiple IP addresses (very common with IPv6), you might additionally need to bind Factorio to a single IP (otherwise the UDP proxy might get confused with IP mismatches). To do that pass the `BIND` envvar to the container: `docker run --network=host -e BIND=2a02:1234::5678 ...` | ||||
|  | ||||
| ## Rootless Docker Support | ||||
|  | ||||
| If you're experiencing permission issues or want better security, consider using the rootless images. These images are designed to work seamlessly with rootless Docker installations and avoid common permission problems. | ||||
|  | ||||
| ### Rootless Image Tags | ||||
|  | ||||
| Each regular tag has a corresponding rootless version with the `-rootless` suffix: | ||||
| - `latest-rootless` | ||||
| - `stable-rootless`   | ||||
| - `2.0.55-rootless` | ||||
|  | ||||
| ### Quick Start with Rootless | ||||
|  | ||||
| ```shell | ||||
| docker run -d \ | ||||
|   -p 34197:34197/udp \ | ||||
|   -p 27015:27015/tcp \ | ||||
|   -v ~/factorio:/factorio \ | ||||
|   --name factorio \ | ||||
|   --restart=unless-stopped \ | ||||
|   factoriotools/factorio:stable-rootless | ||||
| ``` | ||||
|  | ||||
| Key differences: | ||||
| - No `chown` command needed | ||||
| - No PUID/PGID environment variables | ||||
| - Runs as UID 1000 by default | ||||
| - No permission issues with volumes | ||||
|  | ||||
| For more information, see the [Rootless Docker documentation](README-ROOTLESS.md). | ||||
|  | ||||
| ## Troubleshooting | ||||
|  | ||||
| ### My server is listed in the server browser, but nobody can connect | ||||
|   | ||||
							
								
								
									
										128
									
								
								build-rootless.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										128
									
								
								build-rootless.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import os | ||||
| import json | ||||
| import subprocess | ||||
| import shutil | ||||
| import sys | ||||
| import tempfile | ||||
|  | ||||
|  | ||||
| PLATFORMS = [ | ||||
|     "linux/arm64", | ||||
|     "linux/amd64", | ||||
| ] | ||||
|  | ||||
|  | ||||
| def create_builder(build_dir, builder_name, platform): | ||||
|     check_exists_command = ["docker", "buildx", "inspect", builder_name] | ||||
|     if subprocess.run(check_exists_command, stderr=subprocess.DEVNULL).returncode != 0: | ||||
|         create_command = ["docker", "buildx", "create", "--platform", platform, "--name", builder_name] | ||||
|         try: | ||||
|             subprocess.run(create_command, cwd=build_dir, check=True) | ||||
|         except subprocess.CalledProcessError: | ||||
|             print("Creating builder failed") | ||||
|             exit(1) | ||||
|  | ||||
|  | ||||
| def build_and_push_multiarch(build_dir, build_args, push): | ||||
|     builder_name = "factoriotools-rootless-multiarch" | ||||
|     platform=",".join(PLATFORMS) | ||||
|     create_builder(build_dir, builder_name, platform) | ||||
|     build_command = ["docker", "buildx", "build", "--platform", platform, "--builder", builder_name] + build_args | ||||
|     if push: | ||||
|         build_command.append("--push") | ||||
|     try: | ||||
|         subprocess.run(build_command, cwd=build_dir, check=True) | ||||
|     except subprocess.CalledProcessError: | ||||
|         print("Build and push of rootless image failed") | ||||
|         exit(1) | ||||
|  | ||||
|  | ||||
| def build_singlearch(build_dir, build_args): | ||||
|     build_command = ["docker", "build"] + build_args | ||||
|     try: | ||||
|         subprocess.run(build_command, cwd=build_dir, check=True) | ||||
|     except subprocess.CalledProcessError: | ||||
|         print("Build of rootless image failed") | ||||
|         exit(1) | ||||
|  | ||||
|  | ||||
| def push_singlearch(tags): | ||||
|     for tag in tags: | ||||
|         try: | ||||
|             subprocess.run(["docker", "push", f"factoriotools/factorio:{tag}"], | ||||
|                             check=True) | ||||
|         except subprocess.CalledProcessError: | ||||
|             print("Docker push failed") | ||||
|             exit(1) | ||||
|  | ||||
|  | ||||
| def build_and_push(sha256, version, tags, push, multiarch): | ||||
|     build_dir = tempfile.mktemp() | ||||
|     shutil.copytree("docker", build_dir) | ||||
|     # Use the rootless Dockerfile | ||||
|     build_args = ["-f", "Dockerfile.rootless", "--build-arg", f"VERSION={version}", "--build-arg", f"SHA256={sha256}", "."] | ||||
|     for tag in tags: | ||||
|         build_args.extend(["-t", f"factoriotools/factorio:{tag}"]) | ||||
|     if multiarch: | ||||
|         build_and_push_multiarch(build_dir, build_args, push) | ||||
|     else: | ||||
|         build_singlearch(build_dir, build_args) | ||||
|         if push: | ||||
|             push_singlearch(tags) | ||||
|  | ||||
|  | ||||
| def login(): | ||||
|     try: | ||||
|         username = os.environ["DOCKER_USERNAME"] | ||||
|         password = os.environ["DOCKER_PASSWORD"] | ||||
|         subprocess.run(["docker", "login", "-u", username, "-p", password], check=True) | ||||
|     except KeyError: | ||||
|         print("Username and password need to be given") | ||||
|         exit(1) | ||||
|     except subprocess.CalledProcessError: | ||||
|         print("Docker login failed") | ||||
|         exit(1) | ||||
|  | ||||
|  | ||||
| def generate_rootless_tags(original_tags): | ||||
|     """Generate rootless-specific tags from original tags""" | ||||
|     rootless_tags = [] | ||||
|     for tag in original_tags: | ||||
|         # Add -rootless suffix to each tag | ||||
|         rootless_tags.append(f"{tag}-rootless") | ||||
|     return rootless_tags | ||||
|  | ||||
|  | ||||
| def main(push_tags=False, multiarch=False): | ||||
|     with open(os.path.join(os.path.dirname(__file__), "buildinfo.json")) as file_handle: | ||||
|         builddata = json.load(file_handle) | ||||
|  | ||||
|     if push_tags: | ||||
|         login() | ||||
|  | ||||
|     # Build only the latest stable and experimental versions for rootless | ||||
|     versions_to_build = [] | ||||
|      | ||||
|     # Find latest stable and experimental versions | ||||
|     for version, buildinfo in builddata.items(): | ||||
|         if "stable" in buildinfo["tags"] or "latest" in buildinfo["tags"]: | ||||
|             versions_to_build.append((version, buildinfo)) | ||||
|      | ||||
|     for version, buildinfo in versions_to_build: | ||||
|         sha256 = buildinfo["sha256"] | ||||
|         original_tags = buildinfo["tags"] | ||||
|         rootless_tags = generate_rootless_tags(original_tags) | ||||
|         build_and_push(sha256, version, rootless_tags, push_tags, multiarch) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     push_tags = False | ||||
|     multiarch = False | ||||
|     for arg in sys.argv[1:]: | ||||
|         if arg == "--push-tags": | ||||
|             push_tags = True | ||||
|         elif arg == "--multiarch": | ||||
|             multiarch = True | ||||
|     main(push_tags, multiarch) | ||||
							
								
								
									
										93
									
								
								docker/Dockerfile.rootless
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								docker/Dockerfile.rootless
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| # build rcon client | ||||
| FROM debian:stable-slim AS rcon-builder | ||||
| RUN apt-get -q update \ | ||||
|     && DEBIAN_FRONTEND=noninteractive apt-get -qy install build-essential | ||||
|  | ||||
| WORKDIR /src | ||||
| COPY rcon/ /src | ||||
| RUN make | ||||
|  | ||||
| # build factorio image | ||||
| FROM debian:stable-slim | ||||
| LABEL maintainer="https://github.com/factoriotools/factorio-docker" | ||||
|  | ||||
| ARG BOX64_VERSION=v0.2.4 | ||||
|  | ||||
| # optionally utilize a built-in map-gen-preset (see data/base/prototypes/map-gen-presets | ||||
| ARG PRESET | ||||
|  | ||||
| # number of retries that curl will use when pulling the headless server tarball | ||||
| ARG CURL_RETRIES=8 | ||||
|  | ||||
| ENV PORT=34197 \ | ||||
|     RCON_PORT=27015 \ | ||||
|     SAVES=/factorio/saves \ | ||||
|     PRESET="$PRESET" \ | ||||
|     CONFIG=/factorio/config \ | ||||
|     MODS=/factorio/mods \ | ||||
|     SCENARIOS=/factorio/scenarios \ | ||||
|     SCRIPTOUTPUT=/factorio/script-output \ | ||||
|     DLC_SPACE_AGE="true" | ||||
|  | ||||
| SHELL ["/bin/bash", "-eo", "pipefail", "-c"] | ||||
|  | ||||
| RUN apt-get -q update \ | ||||
|     && DEBIAN_FRONTEND=noninteractive apt-get -qy install ca-certificates curl jq pwgen xz-utils procps gettext-base --no-install-recommends \ | ||||
|     && if [[ "$(uname -m)" == "aarch64" ]]; then \ | ||||
|         echo "installing ARM compatability layer" \ | ||||
|         && DEBIAN_FRONTEND=noninteractive apt-get -qy install unzip --no-install-recommends \  | ||||
|         && curl -LO https://github.com/ptitSeb/box64/releases/download/${BOX64_VERSION}/box64-GENERIC_ARM-RelWithDebInfo.zip \ | ||||
|         && unzip box64-GENERIC_ARM-RelWithDebInfo.zip -d /bin \ | ||||
|         && rm -f box64-GENERIC_ARM-RelWithDebInfo.zip \ | ||||
|         && chmod +x /bin/box64; \ | ||||
|     fi \ | ||||
|     && rm -rf /var/lib/apt/lists/* | ||||
|  | ||||
| # version checksum of the archive to download | ||||
| ARG VERSION | ||||
| ARG SHA256 | ||||
|  | ||||
| LABEL factorio.version=${VERSION} | ||||
|  | ||||
| ENV VERSION=${VERSION} \ | ||||
|     SHA256=${SHA256} | ||||
|  | ||||
| RUN set -ox pipefail \ | ||||
|     && if [[ "${VERSION}" == "" ]]; then \ | ||||
|         echo "build-arg VERSION is required" \ | ||||
|         && exit 1; \ | ||||
|     fi \ | ||||
|     && if [[ "${SHA256}" == "" ]]; then \ | ||||
|         echo "build-arg SHA256 is required" \ | ||||
|         && exit 1; \ | ||||
|     fi \ | ||||
|     && archive="/tmp/factorio_headless_x64_$VERSION.tar.xz" \ | ||||
|     && mkdir -p /opt /factorio \ | ||||
|     && curl -sSL "https://www.factorio.com/get-download/$VERSION/headless/linux64" -o "$archive" --retry $CURL_RETRIES \ | ||||
|     && echo "$SHA256  $archive" | sha256sum -c \ | ||||
|     || (sha256sum "$archive" && file "$archive" && exit 1) \ | ||||
|     && tar xf "$archive" --directory /opt \ | ||||
|     && chmod ugo=rwx /opt/factorio \ | ||||
|     && rm "$archive" \ | ||||
|     && ln -s "$SCENARIOS" /opt/factorio/scenarios \ | ||||
|     && ln -s "$SAVES" /opt/factorio/saves \ | ||||
|     && mkdir -p /opt/factorio/config/ | ||||
|  | ||||
| COPY files/*.sh / | ||||
| COPY files/docker-entrypoint-rootless.sh /docker-entrypoint.sh | ||||
| COPY files/config.ini /opt/factorio/config/config.ini | ||||
| COPY --from=rcon-builder /src/rcon /bin/rcon | ||||
|  | ||||
| # Make all scripts executable | ||||
| RUN chmod +x /*.sh | ||||
|  | ||||
| # Set proper permissions for the factorio directory | ||||
| RUN chmod -R 777 /opt/factorio /factorio | ||||
|  | ||||
| VOLUME /factorio | ||||
| EXPOSE $PORT/udp $RCON_PORT/tcp | ||||
|  | ||||
| # Run as non-root user (UID 1000 is common for the first user in rootless containers) | ||||
| USER 1000:1000 | ||||
|  | ||||
| ENTRYPOINT ["/docker-entrypoint.sh"] | ||||
							
								
								
									
										124
									
								
								docker/files/docker-entrypoint-rootless.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										124
									
								
								docker/files/docker-entrypoint-rootless.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| #!/bin/bash | ||||
| set -eoux pipefail | ||||
| INSTALLED_DIRECTORY=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") | ||||
| FACTORIO_VOL=/factorio | ||||
| LOAD_LATEST_SAVE="${LOAD_LATEST_SAVE:-true}" | ||||
| GENERATE_NEW_SAVE="${GENERATE_NEW_SAVE:-false}" | ||||
| PRESET="${PRESET:-""}" | ||||
| SAVE_NAME="${SAVE_NAME:-""}" | ||||
| BIND="${BIND:-""}" | ||||
| CONSOLE_LOG_LOCATION="${CONSOLE_LOG_LOCATION:-""}" | ||||
|  | ||||
| # Create directories if they don't exist | ||||
| # In rootless mode, these should be writable by the container user | ||||
| mkdir -p "$FACTORIO_VOL" | ||||
| mkdir -p "$SAVES" | ||||
| mkdir -p "$CONFIG" | ||||
| mkdir -p "$MODS" | ||||
| mkdir -p "$SCENARIOS" | ||||
| mkdir -p "$SCRIPTOUTPUT" | ||||
|  | ||||
| # Generate RCON password if needed | ||||
| if [[ ! -f $CONFIG/rconpw ]]; then | ||||
|   pwgen 15 1 >"$CONFIG/rconpw" | ||||
| fi | ||||
|  | ||||
| # Copy default configs if they don't exist | ||||
| if [[ ! -f $CONFIG/server-settings.json ]]; then | ||||
|   cp /opt/factorio/data/server-settings.example.json "$CONFIG/server-settings.json" | ||||
| fi | ||||
|  | ||||
| if [[ ! -f $CONFIG/map-gen-settings.json ]]; then | ||||
|   cp /opt/factorio/data/map-gen-settings.example.json "$CONFIG/map-gen-settings.json" | ||||
| fi | ||||
|  | ||||
| if [[ ! -f $CONFIG/map-settings.json ]]; then | ||||
|   cp /opt/factorio/data/map-settings.example.json "$CONFIG/map-settings.json" | ||||
| fi | ||||
|  | ||||
| # Clean up incomplete saves | ||||
| NRTMPSAVES=$( find -L "$SAVES" -iname \*.tmp.zip -mindepth 1 | wc -l ) | ||||
| if [[ $NRTMPSAVES -gt 0 ]]; then | ||||
|   rm -f "$SAVES"/*.tmp.zip | ||||
| fi | ||||
|  | ||||
| # Update mods if requested | ||||
| if [[ ${UPDATE_MODS_ON_START:-} == "true" ]]; then | ||||
|   ${INSTALLED_DIRECTORY}/docker-update-mods.sh | ||||
| fi | ||||
|  | ||||
| # Handle DLC | ||||
| ${INSTALLED_DIRECTORY}/docker-dlc.sh | ||||
|  | ||||
| # In rootless mode, we don't need to handle user switching or chown | ||||
| # The container runs as the specified user from the start | ||||
| EXEC="" | ||||
| if [[ -f /bin/box64 ]]; then | ||||
|   # Use emulator for ARM hosts | ||||
|   EXEC="/bin/box64" | ||||
| fi | ||||
|  | ||||
| # Update config path | ||||
| sed -i '/write-data=/c\write-data=\/factorio/' /opt/factorio/config/config.ini | ||||
|  | ||||
| # Generate new save if needed | ||||
| NRSAVES=$(find -L "$SAVES" -iname \*.zip -mindepth 1 | wc -l) | ||||
| if [[ $GENERATE_NEW_SAVE != true && $NRSAVES ==  0 ]]; then | ||||
|     GENERATE_NEW_SAVE=true | ||||
|     SAVE_NAME=_autosave1 | ||||
| fi | ||||
|  | ||||
| if [[ $GENERATE_NEW_SAVE == true ]]; then | ||||
|     if [[ -z "$SAVE_NAME" ]]; then | ||||
|         echo "If \$GENERATE_NEW_SAVE is true, you must specify \$SAVE_NAME" | ||||
|         exit 1 | ||||
|     fi | ||||
|     if [[ -f "$SAVES/$SAVE_NAME.zip" ]]; then | ||||
|         echo "Map $SAVES/$SAVE_NAME.zip already exists, skipping map generation" | ||||
|     else | ||||
|         if [[ ! -z "$PRESET" ]]; then | ||||
|             $EXEC /opt/factorio/bin/x64/factorio \ | ||||
|                 --create "$SAVES/$SAVE_NAME.zip" \ | ||||
|                 --preset "$PRESET" \ | ||||
|                 --map-gen-settings "$CONFIG/map-gen-settings.json" \ | ||||
|                 --map-settings "$CONFIG/map-settings.json" | ||||
|         else | ||||
|             $EXEC /opt/factorio/bin/x64/factorio \ | ||||
|                 --create "$SAVES/$SAVE_NAME.zip" \ | ||||
|                 --map-gen-settings "$CONFIG/map-gen-settings.json" \ | ||||
|                 --map-settings "$CONFIG/map-settings.json" | ||||
|         fi | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| # Build command flags | ||||
| FLAGS=(\ | ||||
|   --port "$PORT" \ | ||||
|   --server-settings "$CONFIG/server-settings.json" \ | ||||
|   --server-banlist "$CONFIG/server-banlist.json" \ | ||||
|   --rcon-port "$RCON_PORT" \ | ||||
|   --server-whitelist "$CONFIG/server-whitelist.json" \ | ||||
|   --use-server-whitelist \ | ||||
|   --server-adminlist "$CONFIG/server-adminlist.json" \ | ||||
|   --rcon-password "$(cat "$CONFIG/rconpw")" \ | ||||
|   --server-id /factorio/config/server-id.json \ | ||||
|   --mod-directory "$MODS" \ | ||||
| ) | ||||
|  | ||||
| if [ -n "$CONSOLE_LOG_LOCATION" ]; then | ||||
|   FLAGS+=( --console-log "$CONSOLE_LOG_LOCATION" ) | ||||
| fi | ||||
|  | ||||
| if [ -n "$BIND" ]; then | ||||
|   FLAGS+=( --bind "$BIND" ) | ||||
| fi | ||||
|  | ||||
| if [[ $LOAD_LATEST_SAVE == true ]]; then | ||||
|     FLAGS+=( --start-server-load-latest ) | ||||
| else | ||||
|     FLAGS+=( --start-server "$SAVE_NAME" ) | ||||
| fi | ||||
|  | ||||
| # Execute factorio | ||||
| # In rootless mode, we run directly without user switching | ||||
| exec $EXEC /opt/factorio/bin/x64/factorio "${FLAGS[@]}" "$@" | ||||
		Reference in New Issue
	
	Block a user