diff --git a/Config/DNS/docker-compose.yml b/Config/DNS/docker-compose.yml index 2cfd1a9..7b6ae6e 100644 --- a/Config/DNS/docker-compose.yml +++ b/Config/DNS/docker-compose.yml @@ -15,3 +15,12 @@ services: ports: - "53:53/udp" - "53:53/tcp" + deploy: + mode: global + resources: + limits: + cpus: '0.50' + memory: 512M + reservations: + cpus: '0.25' + memory: 128M diff --git a/Config/Hyperling.com/docker-compose.yml b/Config/Hyperling.com/docker-compose.yml index b677d07..48a0045 100644 --- a/Config/Hyperling.com/docker-compose.yml +++ b/Config/Hyperling.com/docker-compose.yml @@ -10,3 +10,9 @@ services: restart: always ports: - 8317:8080 + deploy: + mode: global + resources: + limits: + cpus: '0.25' + memory: 256M diff --git a/Config/MailServer/docker_compose.yml.TBD b/Config/MailServer/docker_compose.yml.TBD new file mode 100644 index 0000000..e69de29 diff --git a/Config/Nextcloud/cron.sh b/Config/Nextcloud/cron.sh new file mode 100755 index 0000000..9de1654 --- /dev/null +++ b/Config/Nextcloud/cron.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# 2023-08-25 Hyperling +# Put the cron command in a script as well as other automation. +# This should be added to root's crontab with the full path, such as: +# */5 * * * * /opt/Docker/Config/Nextcloud/cron.ksh + +# Check if a job is already going. +PROG="$(basename -- "${BASH_SOURCE[0]}")" +RUNNING=`ps -ef | grep $PROG | grep -v grep | grep -v $$ | grep -v "sh -c" | wc -l` +if (( $RUNNING > 0 )); then + exit $RUNNING +fi + +# 2023-08-25 From crontab. +docker exec -u www-data nc-app php cron.php --define apc.enable_cli=1 + +# 2023-08-25 From fixes.sh, keep ownership correct and apps up to date. +docker exec -it nc-app chown -Rc www-data:www-data . +docker exec -itu www-data nc-app ./occ app:update --all + +exit 0 diff --git a/Config/Nextcloud/docker-compose.yml b/Config/Nextcloud/docker-compose.yml index e6f64f6..9b99581 100644 --- a/Config/Nextcloud/docker-compose.yml +++ b/Config/Nextcloud/docker-compose.yml @@ -3,19 +3,25 @@ # https://hub.docker.com/_/nextcloud # Changelog: -# 2023-07-16 Change from mariadb:10.5 to 10.6. -# 2023-08-20 Add Redis. (https://markontech.com/docker/setup-nextcloud-with-redis-using-docker/) -# 2023-08-21 Got NC to work with OO after specifying the Advanced parameters! -# OO Address: https://FQDN-For-Reverse-Proxied-OO-Server -# OO Secret: Contents-Of-$JWT_SECRET -# OO Header: -# OO Internal Address: http://docker-server-ip:8000 -# NC Internal Address: http://docker-server-ip:8080 +# 2023-07-16 +# Change from mariadb:10.5 to 10.6. +# 2023-08-20 +# Add Redis. (https://markontech.com/docker/setup-nextcloud-with-redis-using-docker/) +# 2023-08-21 +# Got NC to work with OO after specifying the Advanced parameters! +# 2023-08-26 +# Try combining OnlyOffice to here again. It has been on its own since +# 2023-07-25 but isn't being used for anything else. OO is slow to respond +# and upgrades can no longer be done separately but this keeps it all easier +# to maintain and may allow the internal address to be based on container +# name instead of the docker hosts's IP. version: '3' services: - db: + + ## MariaDB ## + nc-db: container_name: nc-db image: mariadb:10.6 restart: always @@ -27,29 +33,75 @@ services: - MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD - MYSQL_USER=$MYSQL_USER - MYSQL_PASSWORD=$MYSQL_PASSWORD + deploy: + mode: global + resources: + limits: + cpus: '0.50' + memory: 1G + reservations: + cpus: '0.25' + memory: 256M - redis: + ## Redis ## + nc-redis: container_name: nc-redis image: redis restart: always command: redis-server --requirepass $REDIS_HOST_PASSWORD + deploy: + mode: global + resources: + limits: + cpus: '0.25' + memory: 128M - app: + ## OnlyOffice ## + nc-oo: + container_name: nc-oo + image: onlyoffice/documentserver + restart: always + ports: + - 8081:80 + environment: + - JWT_SECRET=$JWT_SECRET + deploy: + mode: global + resources: + limits: + cpus: '0.75' + memory: 1G + + ## Nextcloud ## + nc-app: container_name: nc-app image: nextcloud restart: always ports: - 8080:80 links: - - db - - redis + - nc-db + - nc-redis + - nc-oo volumes: - ../../Volumes/Nextcloud/nextcloud:/var/www/html environment: + - NEXTCLOUD_ADMIN_USER=$NEXTCLOUD_ADMIN_USER + - NEXTCLOUD_ADMIN_PASSWORD=$NEXTCLOUD_ADMIN_PASSWORD + - PHP_MEMORY_LIMIT=$PHP_MEMORY_LIMIT + - PHP_UPLOAD_LIMIT=$PHP_UPLOAD_LIMIT - MYSQL_HOST=$MYSQL_HOST - MYSQL_DATABASE=$MYSQL_DATABASE - MYSQL_USER=$MYSQL_USER - MYSQL_PASSWORD=$MYSQL_PASSWORD - - PHP_UPLOAD_LIMIT=$PHP_UPLOAD_LIMIT - REDIS_HOST=$REDIS_HOST - REDIS_HOST_PASSWORD=$REDIS_HOST_PASSWORD + deploy: + mode: global + resources: + limits: + cpus: '2.00' + # No memory limit. + reservations: + cpus: '0.50' + memory: 512M diff --git a/Config/Nextcloud/env.example b/Config/Nextcloud/env.example index 7cc9471..f3e1349 100644 --- a/Config/Nextcloud/env.example +++ b/Config/Nextcloud/env.example @@ -1,18 +1,55 @@ -# Example environment file for Nextcloud stack, should be copied as `.env`. +# Example environment file for Nextcloud stack, should be copied as `.env`. The +# variables here only apply to the compose file. If you need it passed to a +# container then it also needs specified in its `environment:` operator. +# +# ** All usernames and passwords need changed before running in production! ** +# +# Full guide on the Nextcloud parameters which may be supplied: +# https://github.com/docker-library/docs/blob/master/nextcloud/README.md#auto-configuration-via-environment-variables +# ## Nextcloud ## +# +NEXTCLOUD_ADMIN_USER=nc_admin +NEXTCLOUD_ADMIN_PASSWORD=SuperDuperSecretPassword + +PHP_MEMORY_LIMIT=2G PHP_UPLOAD_LIMIT=5G -## MySQL ## +# +## MariaDB ## +# +# Should load automatically the first run. Then config.php is the source of +# truth for these values. So, if something like the DB password is changed, +# updating it here will have no effect. This is only used for the install. -MYSQL_HOST=db +MYSQL_HOST=nc-db MYSQL_DATABASE=nextcloud MYSQL_ROOT_PASSWORD=ChangeMe MYSQL_USER=nc MYSQL_PASSWORD=changeme -## REDIS ## +# +## Redis ## +# +# Installs automagically if both of these parameters are supplied. -REDIS_HOST=redis +REDIS_HOST=nc-redis REDIS_HOST_PASSWORD=someredispassword + +# +## OnlyOffice ## +# +# How Nextcloud's ONLYOFFICE Admin Settings should be set up: +# OO Address: https://FQDN-For-Reverse-Proxied-OO-Server +# OO Secret: Contents-Of-$JWT_SECRET +# OO Header: +# OO Internal Address: http://docker-server-ip:8081 ?OR http://nc-oo:8081? +# NC Internal Address: http://docker-server-ip:8080 ?OR http://nc-app:8080? +# +# Documentation which references the variable(s) below, Nextcloud link does not cover them: +# https://helpcenter.onlyoffice.com/installation/docs-configure-jwt.aspx + +# Secret key which is used above in the Nextcloud ONLYOFFICE Administration UI. +JWT_SECRET=abc123 diff --git a/Config/Nextcloud/fixes.sh b/Config/Nextcloud/fixes.sh index 15e0239..ccdf7a0 100755 --- a/Config/Nextcloud/fixes.sh +++ b/Config/Nextcloud/fixes.sh @@ -10,10 +10,6 @@ docker exec -itu www-data nc-app ./occ db:add-missing-columns docker exec -itu www-data nc-app ./occ db:add-missing-indices docker exec -itu www-data nc-app ./occ db:add-missing-primary-keys docker exec -itu www-data nc-app ./occ db:convert-filecache-bigint -docker exec -it nc-app chown -Rc www-data:www-data . - -# 2023-02-12 Just for good measure. -docker exec -itu www-data nc-app ./occ app:update --all # 2023-07-02 # This maybe used to exist, but make sure that Files app is correct. diff --git a/Config/OnlyOffice/docker-compose.yml b/Config/OnlyOffice/docker-compose.yml deleted file mode 100644 index 217ad55..0000000 --- a/Config/OnlyOffice/docker-compose.yml +++ /dev/null @@ -1,15 +0,0 @@ -# 2023-07-25 -# OnlyOffice server, primarily used for Nextcloud. - -version: '3' - -services: - app: - container_name: oo-app - image: onlyoffice/documentserver - restart: always - ports: - - 8000:80 - - 4443:443 - environment: - - JWT_SECRET=$JWT_SECRET diff --git a/Config/OnlyOffice/env.example b/Config/OnlyOffice/env.example deleted file mode 100644 index 3a8d6bc..0000000 --- a/Config/OnlyOffice/env.example +++ /dev/null @@ -1,6 +0,0 @@ -# Example environment file for OnlyOffice, should be copied as `.env`. - -## Relating to the Nextcloud Admin Settings UI ## - -# Secret -JWT_SECRET=abc123 diff --git a/Config/ReverseProxy/docker-compose.yml b/Config/ReverseProxy/docker-compose.yml index 1dad73c..613800e 100644 --- a/Config/ReverseProxy/docker-compose.yml +++ b/Config/ReverseProxy/docker-compose.yml @@ -20,6 +20,15 @@ services: - ../../Volumes/ReverseProxy/letsencrypt:/etc/nginx/letsencrypt - ../../Volumes/ReverseProxy/letsencrypt-certs:/etc/nginx/certs command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" + deploy: + mode: global + resources: + limits: + cpus: '1.00' + memory: 512M + reservations: + cpus: '0.25' + memory: 128M certbot: container_name: rp-certbot @@ -29,3 +38,12 @@ services: - ../../Volumes/ReverseProxy/letsencrypt:/etc/letsencrypt - ../../Volumes/ReverseProxy/letsencrypt-certs:/etc/letsencrypt/nginx entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; cp -rL /etc/letsencrypt/live/* /etc/letsencrypt/nginx/; sleep 12h & wait $${!}; done;'" + deploy: + mode: global + resources: + limits: + cpus: '0.50' + memory: 256M + reservations: + cpus: '0.25' + memory: 128M diff --git a/bin/clean.sh b/bin/clean.sh deleted file mode 100755 index 29689d1..0000000 --- a/bin/clean.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# 2023-08-21 Hyperling -# Clean all unused images and containers. -# https://docs.docker.com/config/pruning/ -# Very helpful during development, nice in a long-running production as well. -# usage: clean.sh - -docker image prune -a - -docker container prune - -docker volume prune - -docker network prune - -exit 0 diff --git a/bin/get_logs.sh b/bin/get_logs.sh index 75964e4..89bb819 100755 --- a/bin/get_logs.sh +++ b/bin/get_logs.sh @@ -5,14 +5,9 @@ ## Setup ## -DIR="`dirname $0`" -PROG=`basename $0` -if [[ $DIR == *"."* ]]; then - DIR="`pwd`" -fi -if [[ -z $DOCKER_HOME ]]; then - DOCKER_HOME="$DIR/.." -fi +DIR="$(dirname -- "${BASH_SOURCE[0]}")" +PROG="$(basename -- "${BASH_SOURCE[0]}")" +source $DIR/../source.env dir=logs date_format="+%Y%m%d-%H%M%S" diff --git a/bin/manage.sh b/bin/manage.sh new file mode 100755 index 0000000..12675da --- /dev/null +++ b/bin/manage.sh @@ -0,0 +1,214 @@ +#!/bin/bash +# 2023-08-26 Hyperling +# Combine all programs which loop over Config into one which takes parameters. + +## Setup ## + +DIR="$(dirname -- "${BASH_SOURCE[0]}")" +PROG="$(basename -- "${BASH_SOURCE[0]}")" +source $DIR/../source.env + +## Functions ## + +function usage() { + # Function to give the usage of the program. + # Parameters: + # 1) The exit code used when leaving. + exit_code=$1 + echo "" + echo -n "Usage: $PROG [-A ( -u | -d | -b | -p | -c | -s )] " 1>&2 + echo "[-i CONTAINER] [-l CONTAINER] [-h]" 1>&2 + cat <<- EOF + + Manage all docker compose subprojects based on parameters. If no + options are given then 'docker ps' is performed and the program exits. + + Parameters - Standalone: + + (ALL) + -A : Equivalent of specifying '-udbpcs' for a full upgrade service. + + (UP) + -u : Start all containers with 'up -d'. + + (DOWN) + -d : Stop and take down all containers with 'down'. + + (BUILD) + -b : Do a 'build' for containers with a 'Dockerfile'. + + (PULL) + -p : Update all containers with 'pull'. + + (CLEAN) + -c : Remove any abandoned Docker objects using the 'prune' commands. + + (STATS) + -s : Tune in to the 'stats' of how each container is running. + + Parameters - Specifying CONTAINER: + Variable can be either the container ID or container name. If (UP) is + also provided then the container does not need to be active, otherwise + the container must be running so that it can be accessed. + + (INTERACT) + -i CONTAINER : Remote into CONTAINER with 'exec -it CONTAINER sh'. + + (LOGS) + -l CONTAINER : Follow the logs of CONTAINER with 'logs -f CONTAINER'. + + Parameters - Other: + + (HELP) + -h : Display this message. + + EOF + exit $exit_code +} + +function check_container() { + # Ensure a container which will be accessed is either running or starting. + # Parameters: + # 1) CONTAINER, either as ID or Name. + # 2) WHy the container is being checked. + container_to_check="$1" + reason_to_check="$2" + + exists=`docker ps | grep -c $container_to_check` + if [[ ( $exists == 0 && -z $up ) || ( -n $down && -z $up ) ]]; then + echo -n "ERROR: $container_to_check was requested for " 1>&2 + echo "$reason_to_check but it is not up or going to be up." 1>&2 + exit 2 + fi + + return +} + +## Parameters ## + +while getopts ':Audbpcsi:l:h' opt; do + case $opt in + A) all="Y" ;; + u) up="Y" ;; + d) down="Y" ;; + b) build="Y" ;; + p) pull="Y" ;; + c) clean="Y" ;; + s) stats="Y" ;; + i) interact="$OPTARG" ;; + l) logs="$OPTARG" ;; + h) usage 0 ;; + *) echo "ERROR: Parameter '$OPTARG' not recognized." 1>&2 && usage 1 ;; + esac +done + +# This is done outside the getopts for readability. +if [[ -n $all ]]; then + up="Y"; down="Y"; build="Y"; pull="Y"; clean="Y"; stats="Y" +fi + +## Validations ## + +# Script will behave poorly if not run with admin privileges. +if [[ $LOGNAME != "root" ]]; then + echo "*************************************************************" + echo "WARNING: Script is intended for root. Please su or sudo/doas." + echo -e "*************************************************************\n" +fi + +# Options which only work if the container exists or is going to be started. +if [[ -n $interact ]]; then + check_container $interact interaction +fi +if [[ -n $logs ]]; then + check_container $logs logs +fi + +## Main ## + +# If no parameters are passed, list all the containers which are running. +if [[ -z $up && -z $down && -z $build && -z $pull && -z $clean + && -z $interact && -z $logs && -z $stats +]]; then + docker ps + exit 0 +fi + +# Otherwise, loop through all the subproject configurations. +if [[ -n $up || -n $down || -n $build || -n $pull ]]; then + cd $DOCKER_HOME/Config + for dir in `ls`; do + # If this is a directory, enter it, otherwise skip to the next listing. + [ -d $dir ] && cd $dir || continue + echo "" + pwd + + # Ensure .env files exist so that all compose variables are populated. + if [[ -e ./env.example && ! -e ./.env ]]; then + echo "WARNING: .env file was not found, copying example as placeholder." + cp -v env.example .env + fi + + # Ensure all configuration files have been created. + if [[ -d ./config ]]; then + ls ./config/*.example 2>/dev/null | while read example; do + real=${example//.example/} + if [[ ! -e $real ]]; then + echo "WARNING: $real was not found, copying $example." + cp -v $example $real + fi + done + fi + + # Shut off container. + if [[ $down == "Y" ]]; then + [ -e docker-compose.yml ] && docker compose down + fi + + # Update container from remote source such as Docker Hub. + if [[ $pull == "Y" ]]; then + [ -e docker-compose.yml ] && docker compose pull + fi + + # Execute commands within the container's Dockerfile. + if [[ $build == "Y" ]]; then + [ -e Dockerfile ] && docker compose build + fi + + # Run the container as a daemon. + if [[ $up == "Y" ]]; then + [ -e docker-compose.yml ] && docker compose up -d + fi + + cd .. + done +fi + +# Dive into a container for running ad hoc commands. +if [[ -n $interact ]]; then + echo -e "\n*** Hopping into $interact ***" + docker exec -it $interact sh +fi + +# Clean every type of Docker object which can be abandoined by Compose. +if [[ -n $clean ]]; then + echo -e "\n*** Cleaning Abandoned Objects ***" + docker image prune -a + docker container prune + docker volume prune + docker network prune +fi + +# Follow the logs of a container. +if [[ -n $logs ]]; then + echo -e "\n*** Following Logs of $logs ***" + docker logs -f $logs +fi + +# Watch a top-level performance and resource monitor. +if [[ -n $stats ]]; then + echo -e "\n*** Tuning Into Stats ***" + docker stats +fi + +exit 0 diff --git a/bin/start.sh b/bin/start.sh deleted file mode 100755 index f42c685..0000000 --- a/bin/start.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# 2022-08-05 Hyperling -# Start all containers. -# usage: start.sh - -## Setup ## - -DIR="`dirname $0`" -PROG=`basename $0` -if [[ $DIR == *"."* ]]; then - DIR="`pwd`" -fi -if [[ -z $DOCKER_HOME ]]; then - DOCKER_HOME="$DIR/.." -fi - -## Main ## - -echo "Starting all containers." - -cd $DOCKER_HOME/Config -for dir in `ls`; do - [ -d $dir ] && cd $dir || continue - echo "" - pwd - [ -e Dockerfile ] && docker compose build - [ -e docker-compose.yml ] && docker compose up -d - cd .. -done - -exit 0 diff --git a/bin/stop.sh b/bin/stop.sh deleted file mode 100755 index eac76f7..0000000 --- a/bin/stop.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# 2022-08-05 Hyperling -# Stop all containers. -# usage: stop.sh - -## Setup ## - -DIR="`dirname $0`" -PROG=`basename $0` -if [[ $DIR == *"."* ]]; then - DIR="`pwd`" -fi -if [[ -z $DOCKER_HOME ]]; then - DOCKER_HOME="$DIR/.." -fi - -## Main ## - -echo "Stopping all containers." - -cd $DOCKER_HOME/Config -for dir in `ls`; do - [ -d $dir ] && cd $dir || continue - echo "" - pwd - [ -e docker-compose.yml ] && docker compose down - cd .. -done - -exit 0 diff --git a/bin/update.sh b/bin/update.sh deleted file mode 100755 index 7ce40ad..0000000 --- a/bin/update.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# 2022-09-25 Hyperling -# Script to update a docker compose image. - -docker compose down -docker compose pull && -docker compose build && -docker compose up -d && -exit 0 - -echo "ERROR: Did not update or start correctly." && -exit 1