diff --git a/README.md b/README.md index 0c2f91b..7c10148 100755 --- a/README.md +++ b/README.md @@ -7,43 +7,43 @@ The configuration files for the Illegal Crime Minecraft server. Follow these steps to set up and configure the project: 1. **Clone the repository**: - + ``` git clone https://gitea.leaf.home.kappeh.org/Homelab/minecraft_server.git cd minecraft_server ``` - + 2. **Create required directories**: See [Directory Setup](#directory-setup) for details. - + 3. **Set up environment variables**: See [Environment Variables](#environment-variables) for details. - + 4. **Import world files**: - + The world for the Fabric server is located at `fabric/data/world`. If you want to use an existing world, copy it to this location before running the container: - + ``` cp path/to/world fabric/data/world ``` - + 5. **Adjust permissions (recommended)**: Run the following commands in the root of the repository, replacing `PUID` and `PGID` with the corresponding values from your `.env` file: - + ``` sudo chown -R PUID:PGID . sudo chmod -R 770 . ``` - + 6. **Start the Docker Compose stack**: To start the services in detached mode, run: - + ``` docker compose up -d ``` - + 7. **Stop the Docker Compose stack**: To stop and remove the running containers, use: - + ``` docker compose down ``` - + ## Directory Setup Make a directory called `schematics` in the root of the repository. This directory is used for storing [WorldEdit](https://worldedit.org/) schematic files. To create it, run: @@ -73,12 +73,11 @@ Then, open `.env` in a text editor and set appropriate values for your setup. |`DCLINK_CHANNEL`|The Discord channel ID where the bot will operate. See [dclink](#dclink) for more information.| |`DCLINK_ROLE`|The ID of the role that the bot will give to Discord members when they link their accounts. See [dclink](#dclink) for more information.| |`DCLINK_TOKEN`|The bot token used for authentication with Discord's API. Ensure this is kept secret and secure.| -|`LUCKPERMS_DB_PASSWORD`|The password for the LuckPerms database. This should be a secure password.| +|`LUCKPERMS_PASSWORD`|The password for the LuckPerms database. This should be a secure password.| Instead of using environment variables, the secrets section of `docker-compose.yml` can be modified to read files instead. This method will likely be used by default in future. ## dclink -This configuration uses [dclink](https://github.com/Kalimero2Team/dclink) to link users' Minecraft accounts and Discord accounts. This is so that a user can gain access to the Minecraft server if they are a member of the configured Discord server. +This configuration uses [dclink](https://github.com/Kalimero2Team/dclink) to link users' Minecraft accounts and Discord accounts. This is so that a user can gain access to the Minecraft server if they are a member of the configured Discord server. For this to work you must first [setup a discord bot](https://github.com/Kalimero2Team/dclink/wiki/Setup-Discord-Bot). Then set the relevant [Environment Variables](#environment-variables). - diff --git a/compose.yml b/compose.yml index 901183e..9fdb0bc 100755 --- a/compose.yml +++ b/compose.yml @@ -5,9 +5,10 @@ services: user: 2015:2015 # minecraft_server:minecraft_server restart: unless-stopped depends_on: - init_volumes: + init: condition: service_completed_successfully - luckperms_db: + restart: true + luckperms: condition: service_healthy restart: true fabric: @@ -20,7 +21,7 @@ services: - rcon_password - forwarding_secret - dclink_token - - luckperms_db_password + - luckperms_password networks: minecraft_server_network: ipv4_address: "10.100.1.3" @@ -48,7 +49,7 @@ services: CFG_DCLINK_CHANNEL: ${DCLINK_CHANNEL} CFG_DCLINK_ROLE: ${DCLINK_ROLE} CFG_DCLINK_TOKEN_FILE: /run/secrets/dclink_token - CFG_LUCKPERMS_DB_PASSWORD_FILE: /run/secrets/luckperms_db_password + CFG_LUCKPERMS_PASSWORD_FILE: /run/secrets/luckperms_password PLUGINS: | https://github.com/dbkynd-minecraft/VelocityPlayerList/releases/download/v1.0/PlayerList-1.0.jar @@ -65,8 +66,9 @@ services: user: 2015:2015 # minecraft_server:minecraft_server restart: unless-stopped depends_on: - init_volumes: + init: condition: service_completed_successfully + restart: true fabric: condition: service_healthy restart: true @@ -90,9 +92,10 @@ services: container_name: minecraft_server_paper restart: unless-stopped depends_on: - init_volumes: + init: condition: service_completed_successfully - luckperms_db: + restart: true + luckperms: condition: service_healthy restart: true healthcheck: @@ -103,7 +106,7 @@ services: secrets: - rcon_password - forwarding_secret - - luckperms_db_password + - luckperms_password networks: minecraft_server_network: ipv4_address: "10.100.1.4" @@ -166,7 +169,7 @@ services: CFG_RCON_PASSWORD_FILE: /run/secrets/rcon_password CFG_FORWARDING_SECRET_FILE: /run/secrets/forwarding_secret - CFG_LUCKPERMS_DB_PASSWORD_FILE: /run/secrets/luckperms_db_password + CFG_LUCKPERMS_PASSWORD_FILE: /run/secrets/luckperms_password PLUGINS: | https://github.com/EssentialsX/Essentials/releases/download/2.20.1/EssentialsX-2.20.1.jar @@ -189,9 +192,10 @@ services: container_name: minecraft_server_fabric restart: unless-stopped depends_on: - init_volumes: + init: condition: service_completed_successfully - luckperms_db: + restart: true + luckperms: condition: service_healthy restart: true healthcheck: @@ -202,7 +206,7 @@ services: secrets: - rcon_password - forwarding_secret - - luckperms_db_password + - luckperms_password networks: minecraft_server_network: ipv4_address: "10.100.1.5" @@ -260,7 +264,7 @@ services: CFG_RCON_PASSWORD_FILE: /run/secrets/rcon_password CFG_FORWARDING_SECRET_FILE: /run/secrets/forwarding_secret - CFG_LUCKPERMS_DB_PASSWORD_FILE: /run/secrets/luckperms_db_password + CFG_LUCKPERMS_PASSWORD_FILE: /run/secrets/luckperms_password MODRINTH_PROJECTS: | badpackets:hjhT2sMz @@ -298,14 +302,15 @@ services: vanilla-permissions:7awQNHzw worldedit:3TQ8W0Ar - luckperms_db: + luckperms: image: postgres:17.4 - container_name: minecraft_server_luckperms_db + container_name: minecraft_server_luckperms user: 2015:2015 # minecraft_server:minecraft_server restart: unless-stopped depends_on: - init_volumes: + init: condition: service_completed_successfully + restart: true healthcheck: test: ["CMD-SHELL", "pg_isready -U luckperms -d luckperms"] interval: 10s @@ -313,7 +318,7 @@ services: start_period: 30s timeout: 10s secrets: - - luckperms_db_password + - luckperms_password networks: minecraft_server_network: ipv4_address: "10.100.1.2" @@ -321,23 +326,35 @@ services: - ${LUCKPERMS_PORT}:5432 volumes: - luckperms_data:/var/lib/postgresql/data:rw + - backups:/backups:rw - /etc/passwd:/etc/passwd:ro - # - ./backups:/backups:rw environment: - POSTGRES_PASSWORD_FILE: /run/secrets/luckperms_db_password + POSTGRES_PASSWORD_FILE: /run/secrets/luckperms_password POSTGRES_USER: luckperms POSTGRES_DB: luckperms PGDATA: /var/lib/postgresql/data/pgdata - init_volumes: - container_name: minecraft_server_init_volumes - image: busybox:1.37.0 - user: root:root - command: /init_volumes.sh + # Helper for dumping sqlite databases during backups + sqlite_helper: + container_name: minecraft_server_sqlite_helper + image: grepular/sqlite3:3.51.2 + user: 0:0 restart: no network_mode: none volumes: - - ./scripts/init_volumes.sh:/init_volumes.sh:ro + - backups:/backups:rw + - velocity_data:/velocity_data:ro + + init: + container_name: minecraft_server_init + image: busybox:1.37.0 + user: root:root + command: /init.sh + restart: no + network_mode: none + volumes: + - ./scripts/init.sh:/init.sh:ro + - backups:/backups:rw # Used for resolving user and group names within the init script - /etc/passwd:/etc/passwd:ro - /etc/group:/etc/group:ro @@ -368,8 +385,8 @@ secrets: environment: FORWARDING_SECRET dclink_token: environment: DCLINK_TOKEN - luckperms_db_password: - environment: LUCKPERMS_DB_PASSWORD + luckperms_password: + environment: LUCKPERMS_PASSWORD volumes: velocity_data: @@ -380,3 +397,4 @@ volumes: paper_data: fabric_data: luckperms_data: + backups: diff --git a/fabric/config/luckperms/luckperms.conf b/fabric/config/luckperms/luckperms.conf index d40cb20..f88ac5f 100755 --- a/fabric/config/luckperms/luckperms.conf +++ b/fabric/config/luckperms/luckperms.conf @@ -100,7 +100,7 @@ data { # Credentials for the database. username = "luckperms" - password = "${CFG_LUCKPERMS_DB_PASSWORD}" + password = "${CFG_LUCKPERMS_PASSWORD}" # These settings apply to the MySQL connection pool. # - The default values will be suitable for the majority of users. diff --git a/paper/plugins/LuckPerms/config.yml b/paper/plugins/LuckPerms/config.yml index b49471a..d11d672 100755 --- a/paper/plugins/LuckPerms/config.yml +++ b/paper/plugins/LuckPerms/config.yml @@ -100,7 +100,7 @@ data: # Credentials for the database. username: luckperms - password: '${CFG_LUCKPERMS_DB_PASSWORD}' + password: '${CFG_LUCKPERMS_PASSWORD}' # These settings apply to the MySQL connection pool. # - The default values will be suitable for the majority of users. diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100755 index 0000000..6be428c --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,273 @@ +#!/usr/bin/env sh + +# Adjustable parameters +## The number of backups to keep +BACKUPS_KEEP=24 + +# Global variables (Do NOT change) +CLEANUP_FABRIC=false +CLEANUP_LUCKPERMS=false +CLEANUP_PAPER=false + +main() { + log_info "=== Backup run started at $(date -u '+%Y-%m-%dT%H:%M:%SZ') ===" + log_info "Keeping last $BACKUPS_KEEP backups" + + check_root_permissions + init_backup + + broadcast_status started + + backup_bluemap || cleanup_failure + backup_fabric || cleanup_failure + backup_luckperms || cleanup_failure + backup_paper || cleanup_failure + backup_schematics || cleanup_failure + backup_velocity || cleanup_failure + + finalize_backup || cleanup_failure + prune_backups + cleanup_success + + broadcast_status finished + + log_info "=== Backup run completed successfully at $(date -u '+%Y-%m-%dT%H:%M:%SZ') ===" +} + +check_root_permissions() { + if [ "$EUID" -ne 0 ]; then + log_error "This script must be run by the root user" + exit 1 + fi + + log_info "Running as root (EUID=$EUID)" +} + +init_backup() { + BACKUP_ID="$(date -u +%Y-%m-%dT%H-%M-%SZ)" + BACKUP_DIR="/backups/$BACKUP_ID" + + log_info "Creating backup directory: $BACKUP_DIR" + + docker compose run --rm init sh -c ' + mkdir -p "$1" && + chown minecraft_server:minecraft_server "$1" + ' -- "$BACKUP_DIR" || { + log_error "Failed to create backup directory $BACKUP_DIR" + exit 1 + } + + log_info "Backup directory created and ownership set" +} + +broadcast_status() { + STATUS="$1" + log_info "Broadcasting backup status: $STATUS" + + if docker compose exec -T fabric true > /dev/null 2>&1; then + docker compose exec -T fabric rcon-cli "tellraw @a [{\"text\":\"Server\",\"color\":\"light_purple\"},{\"text\":\": Backup $STATUS.\",\"color\":\"white\"}]" > /dev/null 2>&1 + fi + if docker compose exec -T paper true > /dev/null 2>&1; then + docker compose exec -T paper rcon-cli "tellraw @a [{\"text\":\"Server\",\"color\":\"light_purple\"},{\"text\":\": Backup $STATUS.\",\"color\":\"white\"}]" > /dev/null 2>&1 + fi +} + +backup_bluemap() { + log_info "Starting Bluemap backup..." + + docker compose run --rm init sh -c ' + cp -a --reflink=auto /bluemap_data "$1" && + cp -a --reflink=auto /bluemap_maps "$1" && + cp -a --reflink=auto /bluemap_web "$1" + ' -- "$BACKUP_DIR" || return 1 + + log_info "Finished Bluemap backup" +} + +backup_fabric() { + log_info "Starting Fabric backup..." + + CLEANUP_FABRIC=false + if docker compose exec -T fabric true > /dev/null 2>&1; then + CLEANUP_FABRIC=true + log_info "Fabric server detected, disabling saves" + + docker compose exec -T fabric rcon-cli save-off > /dev/null 2>&1 + docker compose exec -T fabric rcon-cli save-all > /dev/null 2>&1 + fi + + docker compose run --rm init sh -c ' + mkdir -p "$1"/fabric_data && + cp -a --reflink=auto /fabric_data/g4mespeed "$1"/fabric_data && + cp -a --reflink=auto /fabric_data/fabric-essentials.json "$1"/fabric_data && + cp -a --reflink=auto /fabric_data/world "$1"/fabric_data + ' -- "$BACKUP_DIR" || return 1 + + log_info "Finished Fabric backup" +} + +backup_luckperms() { + log_info "Starting LuckPerms backup..." + + CLEANUP_LUCKPERMS=false + if ! docker compose exec -T luckperms true > /dev/null 2>&1; then + CLEANUP_LUCKPERMS=true + log_info "LuckPerms not running, starting temporary container" + + docker compose up --wait luckperms > /dev/null 2>&1 + fi + + docker compose exec luckperms sh -c ' + pg_dump -U luckperms luckperms > "$1"/luckperms.sql + ' -- "$BACKUP_DIR" || return 1 + + log_info "Finished LuckPerms backup" +} + +backup_paper() { + log_info "Starting Paper backup..." + + CLEANUP_PAPER=false + if docker compose exec -T paper true > /dev/null 2>&1; then + CLEANUP_PAPER=true + log_info "Paper server detected, disabling saves" + + docker compose exec -T paper rcon-cli save-off > /dev/null 2>&1 + docker compose exec -T paper rcon-cli save-all > /dev/null 2>&1 + fi + + docker compose run --rm init sh -c ' + mkdir -p "$1"/paper_data/plugins && + cp -a --reflink=auto /paper_data/plugins/Multiverse-Inventories "$1"/paper_data/plugins && + cp -a --reflink=auto /paper_data/plugins/Essentials "$1"/paper_data/plugins && + cp -a --reflink=auto /paper_data/plugins/PlotSquared "$1"/paper_data/plugins && + cp -a --reflink=auto /paper_data/creative "$1"/paper_data && + cp -a --reflink=auto /paper_data/creative_nether "$1"/paper_data && + cp -a --reflink=auto /paper_data/survival "$1"/paper_data && + cp -a --reflink=auto /paper_data/survival_nether "$1"/paper_data && + cp -a --reflink=auto /paper_data/survival_the_end "$1"/paper_data + ' -- "$BACKUP_DIR" || return 1 + + log_info "Finished Paper backup" +} + +backup_schematics() { + log_info "Starting schematics backup..." + + docker compose run --rm init sh -c ' + cp -a --reflink=auto /schematics "$1" + ' -- "$BACKUP_DIR" || return 1 + + log_info "Finished schematics backup" +} + +backup_velocity() { + log_info "Starting Velocity backup..." + + docker compose run --rm init sh -c 'mkdir -p "$1"/velocity_data/plugins/dclink-velocity' -- "$BACKUP_DIR" || return 1 + + docker compose run --rm sqlite_helper \ + /velocity_data/plugins/dclink-velocity/dclink.db \ + ".backup $BACKUP_DIR/velocity_data/plugins/dclink-velocity/dclink.db" || return 1 + + log_info "Finished Velocity backup" +} + +finalize_backup() { + log_info "Finalizing backup $BACKUP_ID" + + docker compose run --rm init chown -R minecraft_server:minecraft_server "$BACKUP_DIR" || { + log_error "Failed to update ownership of backup files" + return 1 + } + + log_info "Backup ownership updated" + + docker compose run --rm init sh -c ' + ln -sfn "$1" /backups/.latest_tmp && + mv -Tf /backups/.latest_tmp /backups/latest + ' -- "$BACKUP_DIR" || { + log_error "Failed to update /backups/latest symlink" + return 1 + } + + log_info "Updated /backups/latest symlink" +} + +prune_backups() { + BACKUPS_ALL=$(docker compose run --rm init sh -c ' + find /backups -mindepth 1 -maxdepth 1 -type d \ + -name "????-??-??T??-??-??Z" | sort + ') + + BACKUPS_TOTAL=$(echo "$BACKUPS_ALL" | wc -l) + BACKUPS_PRUNE=$((BACKUPS_TOTAL - BACKUPS_KEEP)) + + [ "$BACKUPS_PRUNE" -le 0 ] && BACKUPS_PRUNE=0 + + log_info "Total backups found: $BACKUPS_TOTAL" + log_info "Backups to prune: $BACKUPS_PRUNE" + + echo "$BACKUPS_ALL" | head -n "$BACKUPS_PRUNE" | while read -r OLD_BACKUP_DIR; do + log_info "Removing old backup: $OLD_BACKUP_DIR" + docker compose run --rm init rm -rf "$OLD_BACKUP_DIR" + done +} + +trap cleanup_trap HUP INT QUIT ABRT TERM +cleanup_trap() { + log_info "Backup cancelled by signal" + broadcast_status cancelled + cleanup + delete_backup + exit 0 +} + +cleanup_failure() { + log_info "Running cleanup due to failure" + broadcast_status failed + cleanup + delete_backup + exit 1 +} + +cleanup_success() { + log_info "Running cleanup" + cleanup +} + +cleanup() { + # Ignore specified conditions to ensure cleanup runs to completion uninterrupted + trap '' HUP INT QUIT ABRT TERM + + if [ "$CLEANUP_FABRIC" = true ]; then + log_info "Re-enabling Fabric saves" + docker compose exec -T fabric rcon-cli save-on > /dev/null 2>&1 + fi + + if [ "$CLEANUP_LUCKPERMS" = true ]; then + log_info "Bringing down temporary LuckPerms container" + docker compose stop luckperms > /dev/null 2>&1 + fi + + if [ "$CLEANUP_PAPER" = true ]; then + log_info "Re-enabling Paper saves" + docker compose exec -T paper rcon-cli save-on > /dev/null 2>&1 + fi +} + +delete_backup() { + if ! docker compose run --rm init rm -rf "$BACKUP_DIR"; then + log_error "Failed to remove $BACKUP_DIR" + fi +} + +log_info() { + echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] INFO: $*" +} + +log_error() { + echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] ERROR: $*" >&2 +} + +main diff --git a/scripts/init.sh b/scripts/init.sh new file mode 100755 index 0000000..a660c08 --- /dev/null +++ b/scripts/init.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env sh + +# Define a helper function that runs a command +# If the command fails, the script prints an error message +# and exits immediately. +run() { + # "$@" expands to all arguments passed to this function + # and preserves proper word splitting and quoting. + "$@" || { + echo "Error: command failed: $*" >&2 + exit 1 + } +} + +# Make sure volumes have correct permissions +run chown minecraft_server:minecraft_server /bluemap_data +run chown minecraft_server:minecraft_server /bluemap_web +run chown minecraft_server:minecraft_server /bluemap_maps +run chown minecraft_server:minecraft_server /fabric_data +run chown minecraft_server:minecraft_server /luckperms_data +run chown minecraft_server:minecraft_server /paper_data +run chown minecraft_server:minecraft_server /schematics +run chown minecraft_server:minecraft_server /velocity_data + +# Make sure nested volume mount points exist +run mkdir -p /fabric_data/bluemap/web/maps +run chown minecraft_server:minecraft_server /fabric_data/bluemap +run chown minecraft_server:minecraft_server /fabric_data/bluemap/web +run chown minecraft_server:minecraft_server /fabric_data/bluemap/web/maps + +run mkdir -p /fabric_data/config/worldedit/schematics +run chown minecraft_server:minecraft_server /fabric_data/config +run chown minecraft_server:minecraft_server /fabric_data/config/worldedit +run chown minecraft_server:minecraft_server /fabric_data/config/worldedit/schematics + +run mkdir -p /paper_data/bluemap/web/maps +run chown minecraft_server:minecraft_server /paper_data/bluemap +run chown minecraft_server:minecraft_server /paper_data/bluemap/web +run chown minecraft_server:minecraft_server /paper_data/bluemap/web/maps + +run mkdir -p /paper_data/plugins/WorldEdit/schematics +run chown minecraft_server:minecraft_server /paper_data/plugins +run chown minecraft_server:minecraft_server /paper_data/plugins/WorldEdit +run chown minecraft_server:minecraft_server /paper_data/plugins/WorldEdit/schematics + diff --git a/scripts/init_volumes.sh b/scripts/init_volumes.sh deleted file mode 100755 index 7357a82..0000000 --- a/scripts/init_volumes.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env sh - -# Define a helper function that runs a command -# If the command fails, the script prints an error message -# and exits immediately. -run() { - # "$@" expands to all arguments passed to this function - # and preserves proper word splitting and quoting. - "$@" || { - echo "Error: command failed: $*" >&2 - exit 1 - } -} - -# Ensure required directories exist -run mkdir -p /fabric_data/bluemap/web/maps -run mkdir -p /fabric_data/config/worldedit/schematics -run mkdir -p /paper_data/bluemap/web/maps -run mkdir -p /paper_data/plugins/WorldEdit/schematics - -# Ensure correct permissions of docker volumes -run chown -R minecraft_server:minecraft_server /bluemap_data -run chown -R minecraft_server:minecraft_server /bluemap_web -run chown -R minecraft_server:minecraft_server /bluemap_maps -run chown -R minecraft_server:minecraft_server /fabric_data -run chown -R minecraft_server:minecraft_server /luckperms_data -run chown -R minecraft_server:minecraft_server /paper_data -run chown -R minecraft_server:minecraft_server /schematics -run chown -R minecraft_server:minecraft_server /velocity_data - diff --git a/scripts/run_backup.sh b/scripts/run_backup.sh index ff61cbb..9f99535 100755 --- a/scripts/run_backup.sh +++ b/scripts/run_backup.sh @@ -43,7 +43,7 @@ docker exec illegal_crime_paper rcon-cli save-all PG_USER="luckperms" PG_DB="luckperms" BACKUP_DIR_CONTAINER="/backups/$DATE" -docker exec illegal_crime_luckperms_db pg_dump -U "$PG_USER" -F c -b -v -f "$BACKUP_DIR_CONTAINER/luckperms.sql" "$PG_DB" +docker exec illegal_crime_luckperms pg_dump -U "$PG_USER" -F c -b -v -f "$BACKUP_DIR_CONTAINER/luckperms.sql" "$PG_DB" # Copy WorldEdit schematics cp -r "$PROJECT_DIR/schematics" "$BACKUP_DIR_HOST/" @@ -109,4 +109,3 @@ fi # Update permissions of backed up files chown -R "$PUID:$PGID" "$BACKUPS_DIR_HOST" chmod -R 770 "$BACKUPS_DIR_HOST" - diff --git a/template.env b/template.env index 76d9f2a..ee1bdd9 100755 --- a/template.env +++ b/template.env @@ -6,6 +6,5 @@ DCLINK_GUILD=${CFG_DCLINK_GUILD} DCLINK_CHANNEL=${CFG_DCLINK_CHANNEL} DCLINK_ROLE=${CFG_DCLINK_ROLE} DCLINK_TOKEN=${CFG_DCLINK_TOKEN} -LUCKPERMS_DB_PASSWORD=${CFG_LUCKPERMS_DB_PASSWORD} +LUCKPERMS_PASSWORD=${CFG_LUCKPERMS_PASSWORD} LUCKPERMS_PORT=${CFG_LUCKPERMS_PORT} - diff --git a/velocity/config/plugins/luckperms/config.yml b/velocity/config/plugins/luckperms/config.yml index 3121c23..570e64f 100755 --- a/velocity/config/plugins/luckperms/config.yml +++ b/velocity/config/plugins/luckperms/config.yml @@ -90,7 +90,7 @@ data: # Credentials for the database. username: luckperms - password: '${CFG_LUCKPERMS_DB_PASSWORD}' + password: '${CFG_LUCKPERMS_PASSWORD}' # These settings apply to the MySQL connection pool. # - The default values will be suitable for the majority of users.