diff --git a/.dockerignore b/.dockerignore index 79673e81..c4a0cf73 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,6 +10,10 @@ docker-compose.yml .gitlab-ci.yml # root +.editorconfig +.pylintrc +.venv +.vscode crafty_commander.exe DBCHANGES.md docker-compose.yml.example diff --git a/Dockerfile b/Dockerfile index cb081b62..d835958d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,18 +7,43 @@ LABEL maintainer="Dockerfile created by Zedifus " # Security Patch for CVE-2021-44228 ENV LOG4J_FORMAT_MSG_NO_LOOKUPS=true -# Install Packages And Dependencies -COPY requirements.txt /commander/requirements.txt -RUN apt update \ -&& apt install -y gcc python3 python3-pip libmariadb-dev openjdk-8-jre-headless openjdk-11-jre-headless openjdk-16-jre-headless openjdk-17-jre-headless default-jre \ -&& pip3 install --no-cache-dir -r /commander/requirements.txt +# Create non-root user & required dirs +RUN useradd -M crafty \ + && mkdir /commander \ + && chown -R crafty:root /commander -# Copy Source & copy default config from image -COPY ./ /commander +# Install required system packages +RUN apt-get update \ + && apt-get -y --no-install-recommends install \ + gcc \ + python3 \ + python3-dev \ + python3-pip \ + python3-venv \ + libmariadb-dev \ + default-jre \ + openjdk-8-jre-headless \ + openjdk-11-jre-headless \ + openjdk-16-jre-headless \ + openjdk-17-jre-headless \ + && apt-get autoremove \ + && apt-get clean + +# Switch to service user for installing crafty deps +USER crafty WORKDIR /commander +COPY --chown=crafty:root requirements.txt ./ +RUN python3 -m venv ./.venv \ + && . .venv/bin/activate \ + && pip3 install --no-cache-dir --upgrade setuptools==50.3.2 pip==22.0.3 \ + && pip3 install --no-cache-dir -r requirements.txt \ + && deactivate + +# Copy Source w/ perms & prepare default config from example +COPY --chown=crafty:root ./ ./ RUN mv ./app/config ./app/config_original \ -&& mv ./app/config_original/default.json.example ./app/config_original/default.json \ -&& chmod +x ./docker_launcher.sh + && mv ./app/config_original/default.json.example ./app/config_original/default.json \ + && chmod +x ./docker_launcher.sh # Expose Web Interface port & Server port range EXPOSE 8000 diff --git a/README.md b/README.md index d7fb8648..f3fbb16a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ a web interface for the server administrators to interact with their servers. Cr is compatible with Docker, Linux, Windows 7, Windows 8 and Windows 10. ## Documentation -Temporary documentation available on [GitLab](https://gitlab.com/crafty-controller/crafty-commander/wikis/home) +Documentation available on [wiki.craftycontrol.com](https://craftycontrol.com) ## Meta Project Homepage - https://craftycontrol.com @@ -17,15 +17,33 @@ Discord Server - https://discord.gg/9VJPhCE Git Repository - https://gitlab.com/crafty-controller/crafty-web -## Basic Docker Usage +
-**To get started with docker**, all you need to do is pull the image from this git repository's registry. -This is done by using `docker-compose` or `docker run`(You don't need to clone the Repository and build, like in 3.x ). +## Basic Docker Usage 🐳 -If you have a config folder already from previous local installation or docker setup, the image should mount this volume, if none is present then it will populate its own config folder for you. +With `Crafty Controller 4.0` we have focused on building our DevOps Principles, implementing build automation, and securing our containers, with the hopes of making our Container user's lives abit easier. -### Using the registry image: -The provided image supports both `arm64` and `amd64` out the box, if you have issues though you can build it yourself. +### - Two big changes you will notice is: +- We now provide pre-built images for you guys. +- Containers now run as non-root, using practices used by OpenSwift & Kubernetes (root group perms). + + +---- + +### - To get started with docker 🛫 +All you need to do is pull the image from this git repository's registry. +This is done by using `'docker-compose'` or `'docker run'` (You don't need to clone the Repository and build, like in 3.x ). + +If you have a config folder already from previous local installation or _docker setup_*, the image should mount this volume, if no config present then it will populate its own config folder for you.

+As the Dockerfile uses the permission structure of `crafty:root` **internally** there is no need to worry about matching the `UID` or `GID` on the host system :) +> ***Make sure the ownership permissions on `servers/ backups/ logs/ configs/ imports/` in the `docker/` are not `root:root`, please just chown the dir recursively to your host user.** + +> **Please make sure if you are using a `compose` file, that the above volume mount directories are present, otherwise, docker will just make them and they'll be `root:root` which is not what we want.💀** + +
+ +### - Using the registry image 🌎 +The provided image supports both `arm64` and `amd64` out the box, if you have issues though you can build it yourself with the `compose` file in `docker/`. The image is located at: `registry.gitlab.com/crafty-controller/crafty-commander:latest` | Branch | Status | @@ -50,13 +68,20 @@ or ```bash $ echo | docker login registry.gitlab.com -u --password-stdin ``` -or +or ```bash $ cat ~/my_password.txt | docker login registry.gitlab.com -u --password-stdin ``` Then use one of the following methods: -#### docker-compose.yml +### **docker-compose.yml:** +```sh +# We need to make them because of permissions remember! +$ mkdir docker/backups docker/logs docker/servers docker/config docker/import + +# Make your compose file +$ vim docker-compose.yml +``` ```yml version: '3' @@ -64,40 +89,52 @@ services: crafty: container_name: crafty_commander image: registry.gitlab.com/crafty-controller/crafty-commander:latest + environment: + - TZ=Etc/UTC ports: - "8000:8000" # HTTP - "8443:8443" # HTTPS - "8123:8123" # DYNMAP - "19132:19132/udp" # BEDROCK - - "24000-25600:24000-25600" # MC SERV PORT RANGE + - "25500-25600:25500-25600" # MC SERV PORT RANGE volumes: - ./docker/backups:/commander/backups - ./docker/logs:/commander/logs - ./docker/servers:/commander/servers - ./docker/config:/commander/app/config + - ./docker/import:/commander/import ``` - -#### docker run ```sh +$ docker-compose up -d && docker-compose logs -f +``` +
+ +### **docker run:** +```sh +# We need to make them because of permissions remember! +$ mkdir docker/backups docker/logs docker/servers docker/config docker/import + $ docker run \ --name crafty_commander \ -p 8000:8000 \ -p 8443:8443 \ -p 8123:8123 \ -p 19132:19132/udp \ - -p 24000-25600:24000-25600 \ + -p 25500-25600:25500-25600 \ + -e TZ=Etc/UTC \ -v "/$(pwd)/docker/backups:/commander/backups" \ -v "/$(pwd)/docker/logs:/commander/logs" \ -v "/$(pwd)/docker/servers:/commander/servers" \ -v "/$(pwd)/docker/config:/commander/app/config" \ + -v "/$(pwd)/docker/import:/commander/import" \ registry.gitlab.com/crafty-controller/crafty-commander:latest ``` -### Building from the cloned repository: +### **Building from the cloned repository:** If you are building from `docker-compose` you can find the compose file in `./docker/docker-compose.yml` just `cd` to the docker directory and `docker-compose up -d` -If you'd rather not use `docker-compose` you can use the following `docker run`in the directory where the *Dockerfile* is: +If you'd rather not use `docker-compose` you can use the following `docker run` in the directory where the *Dockerfile* is: ```sh # REMEMBER, Build your image first! $ docker build . -t crafty @@ -108,11 +145,13 @@ $ docker run \ -p 8443:8443 \ -p 8123:8123 \ -p 19132:19132/udp \ - -p 24000-25600:24000-25600 \ + -p 25500-25600:25500-25600 \ + -e TZ=Etc/UTC \ -v "/$(pwd)/docker/backups:/commander/backups" \ -v "/$(pwd)/docker/logs:/commander/logs" \ -v "/$(pwd)/docker/servers:/commander/servers" \ -v "/$(pwd)/docker/config:/commander/app/config" \ + -v "/$(pwd)/docker/import:/commander/import" \ crafty ``` -A fresh build will take several minutes depending on your system, but will be rapid there after. +A fresh build will take several minutes depending on your system, but will be rapid thereafter. diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index ee778491..bf0a2137 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -451,7 +451,7 @@ class Controller: server_log_file, server_stop, port, server_type='minecraft-bedrock') if os.name != "nt": if helper.check_file_exists(full_jar_path): - os.chmod(full_jar_path, 2775) + os.chmod(full_jar_path, 0o2775) return new_id def import_bedrock_zip_server(self, server_name: str, zip_path: str, server_exe: str, port: int): @@ -500,7 +500,7 @@ class Controller: server_log_file, server_stop, port, server_type='minecraft-bedrock') if os.name != "nt": if helper.check_file_exists(full_jar_path): - os.chmod(full_jar_path, 2775) + os.chmod(full_jar_path, 0o2775) return new_id diff --git a/docker-compose.yml.example b/docker-compose.yml.example index de5700f1..4de61fd7 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -4,15 +4,17 @@ services: crafty: container_name: crafty_commander image: registry.gitlab.com/crafty-controller/crafty-commander:latest + environment: + - TZ=Etc/UTC ports: - "8000:8000" # HTTP - "8443:8443" # HTTPS - "8123:8123" # DYNMAP - "19132:19132/udp" # BEDROCK - - "24000-25600:24000-25600" # MC SERV PORT RANGE + - "25500-25600:25500-25600" # MC SERV PORT RANGE volumes: - ./docker/backups:/commander/backups - ./docker/logs:/commander/logs - ./docker/servers:/commander/servers - ./docker/config:/commander/app/config - - ./import:/commander/import + - ./docker/import:/commander/import diff --git a/docker/config/.gitkeep b/docker/config/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 5e751d30..cefacb35 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -4,12 +4,14 @@ services: crafty: container_name: crafty_commander build: .. + environment: + - TZ=Etc/UTC ports: - "8000:8000" # HTTP - "8443:8443" # HTTPS - "8123:8123" # DYNMAP - "19132:19132/udp" # BEDROCK - - "24000-25600:24000-25600" # MC SERV PORT RANGE + - "25500-25600:25500-25600" # MC SERV PORT RANGE volumes: - ./backups:/commander/backups - ./logs:/commander/logs diff --git a/docker/import/.gitkeep b/docker/import/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docker_launcher.sh b/docker_launcher.sh index 3cec85fd..08fc81cc 100644 --- a/docker_launcher.sh +++ b/docker_launcher.sh @@ -1,9 +1,11 @@ #!/bin/sh # Check if config exists from existing installation (venv or previous docker launch) -if [ ! "$(ls -A ./app/config)" ]; then +if [ ! "$(ls -A --ignore=.gitkeep ./app/config)" ]; then mkdir ./app/config/ cp -r ./app/config_original/* ./app/config/ fi +# Activate our prepared venv and launch crafty with provided args +. .venv/bin/activate exec python3 main.py $@ diff --git a/main.py b/main.py index b1874422..f3f1078c 100644 --- a/main.py +++ b/main.py @@ -7,14 +7,11 @@ import logging.config import signal from app.classes.shared.console import console from app.classes.shared.helpers import helper -if helper.check_file_exists('/.dockerenv'): - console.cyan("Docker environment detected!") -else: - if helper.checkRoot(): - console.critical("Root detected. Root/Admin access denied. Run Crafty again with non-elevated permissions.") - time.sleep(5) - console.critical("Crafty shutting down. Root/Admin access denied.") - sys.exit(0) +if helper.checkRoot(): + console.critical("Root detected. Root/Admin access denied. Run Crafty again with non-elevated permissions.") + time.sleep(5) + console.critical("Crafty shutting down. Root/Admin access denied.") + sys.exit(0) # pylint: disable=wrong-import-position from app.classes.shared.main_models import installer, database from app.classes.shared.tasks import TasksManager @@ -152,10 +149,10 @@ if __name__ == '__main__': controller.set_project_root(project_root) controller.clear_unexecuted_commands() - def sigterm_handler(): + def sigterm_handler(*sig): print() # for newline - logger.info("Recieved SIGTERM, stopping Crafty") - console.info("Recieved SIGTERM, stopping Crafty") + logger.info(f"Recieved SIGINT [{sig[0]}], stopping Crafty...") + console.info(f"Recieved SIGINT [{sig[0]}], stopping Crafty...") tasks_manager._main_graceful_exit() Crafty.universal_exit() @@ -166,8 +163,8 @@ if __name__ == '__main__': Crafty.cmdloop() except KeyboardInterrupt: print() # for newline - logger.info("Recieved SIGINT, stopping Crafty") - console.info("Recieved SIGINT, stopping Crafty") + logger.info("Recieved SIGINT, stopping Crafty...") + console.info("Recieved SIGINT, stopping Crafty...") tasks_manager._main_graceful_exit() Crafty.universal_exit() else: @@ -178,8 +175,8 @@ if __name__ == '__main__': break time.sleep(1) except KeyboardInterrupt: - logger.info("Recieved SIGINT, stopping Crafty") - console.info("Recieved SIGINT, stopping Crafty") + logger.info("Recieved SIGINT, stopping Crafty...") + console.info("Recieved SIGINT, stopping Crafty...") break tasks_manager._main_graceful_exit() Crafty.universal_exit()