diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca49cbd --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +backup/ +logs/ +plugins/ +.vs/ \ No newline at end of file diff --git a/Backup.ps1 b/Backup.ps1 new file mode 100644 index 0000000..6e383ba --- /dev/null +++ b/Backup.ps1 @@ -0,0 +1,45 @@ +$containerName = "minecraft-server" +$backupDir = "$(pwd)/backup" + +if (-not (Test-Path -Path $backupDir)) { + Write-Host "Creating backup directory: $backupDir" + New-Item -ItemType Directory -Path $backupDir +} + +$container = docker ps -a --filter "name=$containerName" --format "{{.ID}}" +if (-not $container) { + Write-Host "The container $containerName does not exist. Cannot proceed with backup." + exit +} + +$itemsToBackup = @( + "/minecraft/banned-ips.json", + "/minecraft/banned-players.json", + "/minecraft/bukkit.yml", + "/minecraft/help.yml", + "/minecraft/commands.yml", + "/minecraft/ops.json", + "/minecraft/permissions.yml", + "/minecraft/server.properties", + "/minecraft/spigot.yml", + "/minecraft/usercache.json", + "/minecraft/whitelist.json", + "/minecraft/world", + "/minecraft/world_nether", + "/minecraft/world_the_end" +) + +foreach ($item in $itemsToBackup) { + $itemName = [System.IO.Path]::GetFileName($item) + $destination = "$backupDir/$itemName" + Write-Host "Backing up $item to $destination" + if ($item -like "*/world*" -or $item -eq "/minecraft/world" -or $item -eq "/minecraft/world_nether" -or $item -eq "/minecraft/world_the_end") { + Write-Host "Backing up directory $item" + docker cp "$($containerName):$($item)" "$($backupDir)/" + } else { + Write-Host "Backing up file $item" + docker cp "$($containerName):$($item)" "$($destination)" + } +} + +Write-Host "Backup completed successfully." diff --git a/Build.ps1 b/Build.ps1 new file mode 100644 index 0000000..43d5114 --- /dev/null +++ b/Build.ps1 @@ -0,0 +1,25 @@ +$containerName = "minecraft-server" +$imageName = "minecraft-spigot:latest" + +$container = docker ps -a --filter "name=$containerName" --format "{{.ID}}" +if ($container) { + Write-Host "Stopping existing container: $containerName" + docker stop $containerName + Write-Host "Removing existing container: $containerName" + docker rm $containerName +} else { + Write-Host "No existing container found with name: $containerName" +} + +$image = docker images --filter "reference=$imageName" --format "{{.ID}}" +if ($image) { + Write-Host "Removing existing image: $imageName" + docker rmi $imageName +} else { + Write-Host "No existing image found with name: $imageName" +} + +Write-Host "Building new image: $imageName" +docker build -t $imageName . + +Write-Host "Build completed successfully!" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4496f0d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +FROM ubuntu:latest AS builder + +# Install Spigot dependencies +# This installs normal dependencies, sets up zulu apt repository and installs zulu21-jdk +RUN apt-get update && apt-get install -y \ + curl \ + git \ + wget \ + bash \ + gnupg \ + ca-certificates \ + && curl -s https://repos.azul.com/azul-repo.key | gpg --dearmor -o /usr/share/keyrings/azul.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/azul.gpg] https://repos.azul.com/zulu/deb stable main" | tee /etc/apt/sources.list.d/zulu.list \ + && apt-get update && apt-get install -y zulu21-jdk + +WORKDIR /minecraft + +# Setup spigot.jar +# This downloads BuildTools.jar and uses that to build a new spigot.jar +RUN mkdir buildtools \ + && cd buildtools \ + && wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar \ + && java -jar BuildTools.jar --rev latest \ + && mv spigot-*.jar /minecraft/spigot.jar \ + && rm -rf /minecraft/buildtools + +# Accept EULA +RUN echo "eula=true" > /minecraft/eula.txt + +FROM alpine:latest AS runner + +COPY --from=builder /minecraft /minecraft + +RUN apk add --no-cache openjdk21-jre eudev + +WORKDIR /minecraft + +# Move spigot to server directory +EXPOSE 25565 + +CMD /bin/sh -c "java -Xmx2G -Xms512M -jar /minecraft/spigot.jar nogui > /minecraft/logs/output.log 2> /minecraft/logs/error.log" \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..a53bf0d --- /dev/null +++ b/Readme.md @@ -0,0 +1,29 @@ +# Docker image for minecraft servers + +**Requires docker and powershell** + +## First run + +- Run `Build.ps1` to build the image +- Run `mkdir plugins` +- Copy your plugins into `plugins` folder +- Run `Start.ps1` +- Run `Backup.ps1` +- Run `Stop.ps1` +- Edit your server files in the `backup` directory. *Edit stuff such as password, commands, etc.* **The container needs to exist for this to work** +- Run `Restore.ps1` to restore your modified files into the container. **The container needs to run for this to work** +- Run `Start.ps1` +- Check `logs` folder for logs. `output.log` and `error.log` contain the *stdout* and *stderr* of the java process + +## Script glossary + +### `Build.ps1` to build the docker image +If the server is currently running, it will be stopped and rebuilt. **Any changes in the docker container will be lost. Backup your files before building** +### `Start.ps1` to start the server +### `Stop.ps1` to stop the server +### `Backup.ps1` to create a backup of the minecraft files +- If the container does not exist, backup will fail +- If the container exists, your files will be placed in `/backup/` folder +### `Restore.ps1` to restore your minecraft files onto the server +- If the container does not exist, restore will fail +- If the container exists, your files will be restored from `/backup/` folder to the server container \ No newline at end of file diff --git a/Restore.ps1 b/Restore.ps1 new file mode 100644 index 0000000..45fadbe --- /dev/null +++ b/Restore.ps1 @@ -0,0 +1,60 @@ +$containerName = "minecraft-server" +$backupDir = "$(pwd)/backup" + +if (-not (Test-Path -Path $backupDir)) { + Write-Host "Backup directory does not exist: $backupDir" + exit +} + +$container = docker ps -a --filter "name=$containerName" --format "{{.ID}}" +if (-not $container) { + Write-Host "The container $containerName does not exist. Cannot proceed with restore." + exit +} + +$container = docker ps --filter "name=$containerName" --filter "status=running" --format "{{.ID}}" +if ($container) { + Write-Host "Stopping the running container: $containerName" + docker stop $containerName +} else { + Write-Host "The container $containerName is not running." +} + +$itemsToRestore = @( + "banned-ips.json", + "banned-players.json", + "bukkit.yml", + "help.yml", + "commands.yml", + "ops.json", + "permissions.yml", + "server.properties", + "spigot.yml", + "usercache.json", + "whitelist.json", + "world", + "world_nether", + "world_the_end" +) + +foreach ($item in $itemsToRestore) { + $source = "$backupDir/$item" + $destination = "/minecraft/$item" + Write-Host "Restoring $item from $source to $destination" + if (Test-Path $source) { + if ((Get-Item $source).PSIsContainer) { + Write-Host "Restoring directory $item" + docker cp "$source" "$($containerName):/minecraft" + } else { + Write-Host "Restoring file $item" + docker cp "$source" "$($containerName):$destination" + } + } else { + Write-Host "File or directory $item does not exist in the backup." + } +} + +Write-Host "Starting the container: $containerName" +docker start $containerName + +Write-Host "Restore and restart completed successfully." diff --git a/Start.ps1 b/Start.ps1 new file mode 100644 index 0000000..d808f7e --- /dev/null +++ b/Start.ps1 @@ -0,0 +1,26 @@ +$containerName = "minecraft-server" +$imageName = "minecraft-spigot:latest" + +$container = docker ps -a --filter "name=$containerName" --format "{{.ID}}" +if ($container) { + $isRunning = docker ps --filter "name=$containerName" --filter "status=running" --format "{{.ID}}" + if ($isRunning) { + Write-Host "The container '$containerName' is already running." + } else { + Write-Host "The container '$containerName' exists but is not running. Starting it..." + docker start $containerName + } +} else { + Write-Host "The container '$containerName' does not exist. Creating it..." + docker create --name $containerName ` + -p 25565:25565 ` + -v "$(pwd)/plugins:/minecraft/plugins" ` + -v "$(pwd)/logs:/minecraft/logs" ` + --restart unless-stopped ` + minecraft-spigot + + Write-Host "Starting the container '$containerName'..." + docker start $containerName +} + +Write-Host "Server running at 25565..." diff --git a/Stop.ps1 b/Stop.ps1 new file mode 100644 index 0000000..201c070 --- /dev/null +++ b/Stop.ps1 @@ -0,0 +1,15 @@ +$containerName = "minecraft-server" +$container = docker ps -a --filter "name=$containerName" --format "{{.ID}}" +if ($container) { + $isRunning = docker ps --filter "name=$containerName" --filter "status=running" --format "{{.ID}}" + if ($isRunning) { + Write-Host "The container '$containerName' is running. Stopping it..." + docker stop $containerName + } else { + Write-Host "The container '$containerName' exists but is not running." + } +} else { + Write-Host "No container found with name: $containerName" +} + +Write-Host "Stopped"