Compare commits

..

10 commits

13 changed files with 371 additions and 29 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
config/

View file

@ -1,28 +1,36 @@
FROM steamcmd/steamcmd:latest
FROM steamcmd/steamcmd:debian
ENV PORT=7777
ENV UID=568
ENV GID=568
ENV HOME_DIR=/home/steam
ENV SERVER=$HOME_DIR/server
ENV CONFIGS=$HOME_DIR/.config/SCP\ Secret\ Laboratory/config/$PORT
ENV INSTALL_DIR=/home/steam
ENV SERVER_DIR=${INSTALL_DIR}/server
ENV CONFIG_DIR=${INSTALL_DIR}/.config
ENV CONFIG_TEMPLATES_DIR=${INSTALL_DIR}/config-templates
# Default UID/GID that can be overridden at runtime
ENV UID=1000
ENV GID=1000
# Default timezone is UTC
ENV TZ=Etc/UTC
RUN mkdir -p $HOME_DIR $SERVER
# Set the Depot ID for the server
ENV DEPOT_ID=996562
# Set a specific manifest ID to download an older version of the server, defaults to latest version
ENV MANIFEST_ID=7306793446776857728
# Install dependencies
RUN apt-get update && \
apt-get install -y libicu-dev
apt-get install -y libicu-dev gosu && \
rm -rf /var/lib/apt/lists/*
# Create a new group and user
RUN addgroup --gid $GID steam && \
adduser --disabled-password --gecos '' --uid $UID --gid $GID steam
# Create directories (but don't create the user yet)
RUN mkdir -p ${CONFIG_TEMPLATES_DIR}
COPY config-templates/ ${CONFIG_TEMPLATES_DIR}/
# Copy and prepare scripts
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
COPY start.sh /start.sh
COPY config_gameplay.txt $CONFIGS/config_gameplay.txt
COPY config_remoteadmin.txt $CONFIGS/config_remoteadmin.txt
COPY config_localadmin_global.txt $CONFIGS/../config_localadmin_global.txt
COPY localadmin_internal_data.json $CONFIGS/../localadmin_internal_data.json
RUN chmod +x /start.sh
# Change ownership of directories and set the start script as executable
RUN chown $UID:$GID -R $HOME_DIR /usr/lib/games/steam/
ENTRYPOINT /bin/sh /start.sh
# User will be created at runtime based on ENV values
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2023 Matthew Green
Copyright (c) 2025 Matthew Green
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

97
Makefile Normal file
View file

@ -0,0 +1,97 @@
# Configuration
IMAGE_NAME := greenmatthew/scp-secret-laboratory-server
VERSION := 1.0.1
CONTAINER_NAME := scp-sl-server
PORT := 7777
SHELL := /bin/sh
DOCKER_USERNAME ?= greenmatthew
# Default goal
.PHONY: all
all: build
# Build the Docker image
.PHONY: build
build:
@echo "Building Docker image: $(IMAGE_NAME):$(VERSION)"
docker build -t $(IMAGE_NAME):$(VERSION) .
docker tag $(IMAGE_NAME):$(VERSION) $(IMAGE_NAME):latest
# Run the container
.PHONY: run
run: build
@echo "Running container: $(CONTAINER_NAME)"
docker run -d --name $(CONTAINER_NAME) \
-p $(PORT):$(PORT)/udp \
-v $(PWD)/config:/home/steam/.config \
-e TZ=America/Chicago \
-e UID=1001 \
-e GID=1001 \
--restart unless-stopped \
$(IMAGE_NAME):latest
# Get a shell inside the container
.PHONY: shell
shell:
@echo "Executing shell in container: $(CONTAINER_NAME)"
docker exec -it $(CONTAINER_NAME) $(SHELL)
# Stop the container
.PHONY: stop
stop:
@echo "Stopping container: $(CONTAINER_NAME)"
-docker stop $(CONTAINER_NAME)
-docker rm $(CONTAINER_NAME)
# Restart the container
.PHONY: restart
restart: stop run
# Push to Docker Hub
.PHONY: push
push:
@echo "Pushing to Docker Hub: $(IMAGE_NAME):$(VERSION) and $(IMAGE_NAME):latest"
docker push $(IMAGE_NAME):$(VERSION)
docker push $(IMAGE_NAME):latest
# Login to Docker Hub
.PHONY: login
login:
@echo "Logging into Docker Hub..."
docker login -u $(DOCKER_USERNAME)
# Remove Docker image
.PHONY: clean
clean: stop
@echo "Removing Docker image: $(IMAGE_NAME)"
-docker rmi $(IMAGE_NAME):$(VERSION)
-docker rmi $(IMAGE_NAME):latest
# Show help
.PHONY: help
help:
@echo "Available targets:"
@echo " all (default) - Build the Docker image"
@echo " build - Build the Docker image"
@echo " run - Run the container"
@echo " shell - Get a shell inside the running container"
@echo " stop - Stop and remove the container"
@echo " restart - Restart the container"
@echo " push - Push the image to Docker Hub"
@echo " login - Login to Docker Hub"
@echo " clean - Stop container and remove images"
@echo " logs - View container logs"
@echo " help - Show this help message"
@echo ""
@echo "Configuration:"
@echo " IMAGE_NAME = $(IMAGE_NAME)"
@echo " VERSION = $(VERSION)"
@echo " CONTAINER_NAME = $(CONTAINER_NAME)"
@echo " PORT = $(PORT)"
@echo " SHELL = $(SHELL)"
@echo " DOCKER_USERNAME = $(DOCKER_USERNAME)"
# View container logs
.PHONY: logs
logs:
docker logs -f $(CONTAINER_NAME)

134
README.md
View file

@ -1 +1,133 @@
# scp-secret-laboratory-docker
# SCP: Secret Laboratory Docker Server
A Docker container for easily running an SCP: Secret Laboratory dedicated server made by (Matthew Green)[https://git.matthewgreen.gg/mgreen/scp-secret-laboratory-server-docker] and slightly modified by me to add an option to select the manifest version.
## Quick Start
<details open>
<summary><b>Using Docker Compose (Recommended)</b></summary>
1. Create a `docker-compose.yml` file:
```yaml
services:
scp-sl-server:
image: greenmatthew/scp-secret-laboratory-server:latest
container_name: scp-sl-server
ports:
- "7777:7777/udp"
volumes:
- ./config:/home/steam/.config
environment:
- UID=1000
- GID=1000
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List).
# - TZ=Etc/UTC
# To use a specific server version, uncomment the next line and set a manifest ID.
# See the "Using an Older Server Version" section for details.
# - MANIFEST_ID=none
restart: unless-stopped
```
2. Start the server:
```bash
docker-compose up -d
```
3. Check logs:
```bash
docker-compose logs -f
```
</details>
<details>
<summary><b>Using Docker CLI</b></summary>
1. Pull the image:
```bash
docker pull greenmatthew/scp-secret-laboratory-server:latest
```
2. Run the server:
```bash
docker run -d \
--name scp-sl-server \
-p 7777:7777/udp \
-v ./config:/home/steam/.config \
-e UID=1000 \
-e GID=1000 \
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List).
# -e TZ=Etc/UTC \
# To use a specific server version, uncomment the next line and set a manifest ID.
# See the "Using an Older Server Version" section for details.
# -e MANIFEST_ID=none \
--restart unless-stopped \
greenmatthew/scp-secret-laboratory-server:latest
```
3. Check logs:
```bash
docker logs -f scp-sl-server
```
</details>
## Configuration
Mounting the .config directory allows you to configure any server setting and have it persist between container restarts.
## Environment Variables
- `UID`: User ID to run the server as (default: 1000)
- `GID`: Group ID to run the server as (default: 1000)
- `TZ`: [Timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List) for the container (default: Etc/UTC). Examples: `America/Chicago`, `Europe/London`, `Asia/Tokyo`
- `DEPOT_ID`: The Steam Depot ID for the server files (default: `996562`). This generally should not be changed.
- `MANIFEST_ID`: The Steam Manifest ID for a specific server version (default: `none`). See the "Using an Older Server Version" section for details.
## Using an Older Server Version
You can run an older version of the SCP:SL dedicated server by specifying a manifest ID. This is useful for compatibility with certain mods or for playing on a specific game version.
You can find a list of available manifest IDs on SteamDB. Note that you may need to be logged into Steam (e.g. via the SteamDB browser extension) to see the full list of historical manifests.
[`https://steamdb.info/depot/996562/manifests/`](https://steamdb.info/depot/996562/manifests/)
Once you have a manifest ID, set it using the `MANIFEST_ID` environment variable. When the container starts, it will download and run the server version corresponding to the specified manifest ID. To go back to the latest version, simply remove the `MANIFEST_ID` environment variable or set it back to `none`.
## Port Configuration
The default server port is 7777/UDP. To use a different external port, adjust the port mapping:
<details>
<summary><b>In Docker Compose</b></summary>
```yaml
ports:
- "8777:7777/udp" # Maps external port 8777 to internal port 7777
```
</details>
<details>
<summary><b>In Docker CLI</b></summary>
```bash
-p 8777:7777/udp # Maps external port 8777 to internal port 7777
```
</details>
## Development
A Makefile is included for development:
```bash
# For available commands
make help
```
## License
Released under the MIT License. See [LICENSE](LICENSE) file for details.

18
compose.yaml Normal file
View file

@ -0,0 +1,18 @@
services:
scp-sl-server:
build:
context: .
dockerfile: Dockerfile
container_name: scp-sl-server
ports:
- "7777:7777/udp"
volumes:
- ./config:/home/steam/.config
environment:
- UID=1000
- GID=1000
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List).
# - TZ=Etc/UTC
# To download a specific version of the server, uncomment the next line and set the value to a valid manifest ID.
# - MANIFEST_ID=none
restart: unless-stopped

View file

@ -0,0 +1 @@
{"GitHubPersonalAccessToken":null,"EulaAccepted":"${EulaDateAccepted}","PluginManagerWarningDismissed":false,"LastPluginAliasesRefresh":null,"PluginVersionCache":{},"PluginAliases":{}}

44
entrypoint.sh Normal file
View file

@ -0,0 +1,44 @@
#!/bin/sh
set -e
# Set timezone
if [ ! -z "$TZ" ]; then
echo "Setting timezone to $TZ"
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime
echo $TZ > /etc/timezone
fi
echo "Setting up container with UID:${UID} and GID:${GID}"
# Check if group with GID exists
if getent group ${GID} > /dev/null; then
EXISTING_GROUP=$(getent group ${GID} | cut -d: -f1)
if [ "${EXISTING_GROUP}" != "steam" ]; then
echo "ERROR: GID ${GID} already exists with group name '${EXISTING_GROUP}'" >&2
exit 1
fi
else
groupadd --gid ${GID} steam
fi
# Check if user with UID exists
if getent passwd ${UID} > /dev/null; then
EXISTING_USER=$(getent passwd ${UID} | cut -d: -f1)
if [ "${EXISTING_USER}" != "steam" ]; then
echo "ERROR: UID ${UID} already exists with username '${EXISTING_USER}'" >&2
exit 1
fi
else
useradd -c 'Steam User' -l --uid ${UID} --gid ${GID} --home-dir ${INSTALL_DIR} steam
fi
# Get username for the UID
USER_NAME=$(getent passwd ${UID} | cut -d: -f1)
mkdir -p ${SERVER_DIR} ${CONFIG_DIR}
# Ensure correct ownership of all directories
chown -R ${UID}:${GID} ${INSTALL_DIR} ${SERVER_DIR} ${CONFIG_TEMPLATES_DIR}
chmod -R 775 ${CONFIG_DIR}
# Now run the actual script as the specified user
exec gosu steam /start.sh

View file

@ -1,10 +1,51 @@
echo "Current user is: $(whoami)"
steamcmd +force_install_dir $SERVER +login anonymous +app_update 996560 validate +quit
#!/bin/sh
set -e
chown steam:steam -R $HOME_DIR
su - steam
echo "Current user is: $(whoami)"
cd $SERVER
export HOME=$HOME_DIR
./LocalAdmin $PORT --config $CONFIGS
# Install/update SCP:SL server
if [ "$MANIFEST_ID" = "none" ]; then
echo "MANIFEST_ID not set, downloading latest server version..."
steamcmd +force_install_dir $SERVER_DIR +login anonymous +app_update 996560 validate +quit
else
echo "MANIFEST_ID set to $MANIFEST_ID, downloading specific server version..."
# download_depot downloads to a specific folder, not the one specified by force_install_dir
# It will be downloaded to <install_dir>/steamapps/content/app_<id>/depot_<id>
steamcmd +login anonymous +download_depot 996560 $DEPOT_ID $MANIFEST_ID +quit
DEPOT_DOWNLOAD_DIR="$INSTALL_DIR/steamapps/content/app_996560/depot_$DEPOT_ID"
if [ -d "$DEPOT_DOWNLOAD_DIR" ] && [ "$(ls -A "$DEPOT_DOWNLOAD_DIR")" ]; then
echo "Depot downloaded successfully. Clearing server directory..."
find "$SERVER_DIR" -mindepth 1 -delete
echo "Copying downloaded files from $DEPOT_DOWNLOAD_DIR to $SERVER_DIR"
cp -rT "$DEPOT_DOWNLOAD_DIR" "$SERVER_DIR"
echo "Successfully copied files."
else
echo "Error: Depot download failed or the directory is empty." >&2
echo "Please check MANIFEST_ID ($MANIFEST_ID) and DEPOT_ID ($DEPOT_ID)" >&2
exit 1
fi
fi
# Ensure config directory exists
INTERNAL_CONFIG_SUBDIR="$CONFIG_DIR/SCP Secret Laboratory/config/"
mkdir -p "$INTERNAL_CONFIG_SUBDIR"
# Process the internal data template to accept EULA
INTERNAL_DATA_TEMPLATE_FILE="$CONFIG_TEMPLATES_DIR/localadmin_internal_data.json.template"
INTERNAL_DATA_FILE="$INTERNAL_CONFIG_SUBDIR/localadmin_internal_data.json"
if [ ! -f "$INTERNAL_DATA_FILE" ]; then
echo "Creating \`localadmin_internal_data.json\` file with EULA acceptance..."
# Get current date in the correct format
CURRENT_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.%7NZ")
# Replace placeholder in template
sed "s/\${EulaDateAccepted}/$CURRENT_DATE/g" "$INTERNAL_DATA_TEMPLATE_FILE" > "$INTERNAL_DATA_FILE"
chmod 644 "$INTERNAL_DATA_FILE"
echo "Successfully created \`localadmin_internal_data.json\` file with EULA acceptance."
fi
# Run server
cd $SERVER_DIR && HOME=$INSTALL_DIR ./LocalAdmin $PORT
sleep infinity