diff --git a/docker/Dockerfile b/docker/Dockerfile index 28347e3..dda54c0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -18,8 +18,6 @@ ARG SENTRY_DSN ENV BUILD_COMMIT="${BUILD_COMMIT:-dev}" \ BUILD_VERSION="${BUILD_VERSION:-0.0.0}" \ - CGO_ENABLED=0 \ - GO111MODULE=on \ GOPRIVATE="${GOPRIVATE:-}" \ GOPROXY="${GOPROXY:-}" \ SENTRY_DSN="${SENTRY_DSN:-}" @@ -43,19 +41,22 @@ COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica. COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt # These acmesh vars are defined in the base image -ENV SUPPRESS_NO_CONFIG_WARNING=1 \ - S6_LOGGING=0 \ - ACMESH_CONFIG_HOME=/data/.acme.sh/config \ +ENV ACMESH_CONFIG_HOME=/data/.acme.sh/config \ ACMESH_HOME=/data/.acme.sh \ CERT_HOME=/data/.acme.sh/certs \ LE_CONFIG_HOME=/data/.acme.sh/config \ - LE_WORKING_DIR=/data/.acme.sh + LE_WORKING_DIR=/data/.acme.sh \ + S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \ + S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \ + S6_FIX_ATTRS_HIDDEN=1 \ + S6_KILL_FINISH_MAXTIME=10000 \ + S6_VERBOSITY=1 RUN echo "fs.file-max = 65535" > /etc/sysctl.conf # fail2ban RUN apt-get update \ - && apt-get install -y --no-install-recommends fail2ban \ + && apt-get install -y --no-install-recommends fail2ban logrotate \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /etc/fail2ban diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 4f4a5ea..970d86f 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -8,24 +8,25 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"] ARG GOPROXY ARG GOPRIVATE -ENV GOPROXY=$GOPROXY \ - GOPRIVATE=$GOPRIVATE \ - S6_LOGGING=0 \ - SUPPRESS_NO_CONFIG_WARNING=1 \ - ACMESH_CONFIG_HOME=/data/.acme.sh/config \ +ENV ACMESH_CONFIG_HOME=/data/.acme.sh/config \ ACMESH_HOME=/data/.acme.sh \ CERT_HOME=/data/.acme.sh/certs \ + GOPROXY=$GOPROXY \ + GOPRIVATE=$GOPRIVATE \ LE_CONFIG_HOME=/data/.acme.sh/config \ LE_WORKING_DIR=/data/.acme.sh \ - CGO_ENABLED=0 \ - GO111MODULE=on + S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \ + S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \ + S6_FIX_ATTRS_HIDDEN=1 \ + S6_KILL_FINISH_MAXTIME=10000 \ + S6_VERBOSITY=2 RUN echo "fs.file-max = 65535" > /etc/sysctl.conf # node, fail2ban RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \ && apt-get update \ - && apt-get install -y --no-install-recommends nodejs vim dnsutils fail2ban \ + && apt-get install -y --no-install-recommends nodejs vim dnsutils fail2ban logrotate \ && npm install --location=global yarn \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /etc/fail2ban diff --git a/docker/docker-compose.ci.yml b/docker/docker-compose.ci.yml index a9ccd01..d02e868 100644 --- a/docker/docker-compose.ci.yml +++ b/docker/docker-compose.ci.yml @@ -1,5 +1,5 @@ # WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production. -version: "3.8" +version: '3.8' services: fullstack: @@ -7,6 +7,7 @@ services: environment: - NPM_LOG_LEVEL=debug - NPM_LOG_FORMAT=json + - DISABLE_IPV6=true volumes: - '/etc/localtime:/etc/localtime:ro' - npm_data_ci:/data diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index c7ab243..c2f286d 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -1,10 +1,10 @@ # WARNING: This is a DEVELOPMENT docker-compose file used for development of the entire app, it should not be used for production. -version: "3.8" +version: '3.8' services: npm: image: nginxproxymanager:dev - container_name: "npm.dev" + container_name: 'npm.dev' build: context: ../ dockerfile: ./docker/dev/Dockerfile @@ -16,6 +16,7 @@ services: - 3081:81 - 3443:443 environment: + #DEBUG: 'true' DEVELOPMENT: 'true' GOPROXY: "${GOPROXY:-}" GOPRIVATE: "${GOPRIVATE:-}" diff --git a/docker/rootfs/bin/common.sh b/docker/rootfs/bin/common.sh index 413cd91..c89d4e7 100644 --- a/docker/rootfs/bin/common.sh +++ b/docker/rootfs/bin/common.sh @@ -12,6 +12,11 @@ export CYAN BLUE YELLOW RED RESET PUID=${PUID:-0} PGID=${PGID:-0} +NPMUSER=npm +NPMGROUP=npm +NPMHOME=/tmp/npmuserhome +export NPMUSER NPMGROUP NPMHOME + if [[ "$PUID" -ne '0' ]] && [ "$PGID" = '0' ]; then # set group id to same as user id, # the user probably forgot to specify the group id and @@ -38,8 +43,16 @@ log_fatal () { exit 1 } -disable_ipv6 () { - if [ "$DISABLE_IPV6" == 'true' ] || [ "$DISABLE_IPV6" == 'on' ] || [ "$DISABLE_IPV6" == '1' ] || [ "$DISABLE_IPV6" == 'yes' ]; then +# param $1: group_name +get_group_id () { + if [ "${1:-}" != '' ]; then + getent group "$1" | cut -d: -f3 + fi +} + +# param $1: value +is_true () { + if [ "$1" == 'true' ] || [ "$1" == 'on' ] || [ "$1" == '1' ] || [ "$1" == 'yes' ]; then echo '1' else echo '0' diff --git a/docker/rootfs/etc/logrotate.d/nginx-proxy-manager b/docker/rootfs/etc/logrotate.d/nginx-proxy-manager new file mode 100644 index 0000000..20c23ac --- /dev/null +++ b/docker/rootfs/etc/logrotate.d/nginx-proxy-manager @@ -0,0 +1,25 @@ +/data/logs/*_access.log /data/logs/*/access.log { + create 0644 root root + weekly + rotate 4 + missingok + notifempty + compress + sharedscripts + postrotate + /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true + endscript +} + +/data/logs/*_error.log /data/logs/*/error.log { + create 0644 root root + weekly + rotate 10 + missingok + notifempty + compress + sharedscripts + postrotate + /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true + endscript +} \ No newline at end of file diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/backend/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/backend/run index 0098ff6..c90b721 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/backend/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/backend/run @@ -5,18 +5,22 @@ set -e . /bin/common.sh +if [ "$(is_true "$DEBUG")" = '1' ]; then + set -x +fi + log_info 'Starting backend ...' -if [ "$DEVELOPMENT" == "true" ]; then - HOME=/tmp/npmuserhome +if [ "$(is_true "$DEVELOPMENT")" = '1' ]; then + HOME=$NPMHOME GOPATH="$HOME/go" mkdir -p "$GOPATH" - chown -R npmuser:npmuser "$GOPATH" + chown -R "$PUID:$PGID" "$GOPATH" export HOME GOPATH rm -rf /app/backend/.task cd /app/backend || exit 1 - exec s6-setuidgid npmuser task -w + exec s6-setuidgid "$PUID:$PGID" task -w else cd /app/bin || exit 1 - exec s6-setuidgid npmuser /app/bin/server + exec s6-setuidgid "$PUID:$PGID" /app/bin/server fi diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/fail2ban/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/fail2ban/run index a1b2538..adf64ce 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/fail2ban/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/fail2ban/run @@ -3,5 +3,9 @@ . /bin/common.sh +if [ "$(is_true "$DEBUG")" = '1' ]; then + set -x +fi + log_info 'Starting fail2ban ...' exec /usr/bin/fail2ban-client -c /fail2ban -x -vv -f start diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/run index 5911a98..3ae02cd 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/run @@ -3,22 +3,24 @@ set -e -# This service is DEVELOPMENT only. +. /bin/common.sh -if [ "$DEVELOPMENT" == "true" ]; then +if [ "$(is_true "$DEBUG")" = '1' ]; then + set -x +fi + +# This service is DEVELOPMENT only. +if [ "$(is_true "$DEVELOPMENT")" = '1' ]; then CI=true - HOME=/tmp/npmuserhome + HOME=$NPMHOME export CI export HOME - . /bin/common.sh cd /app/frontend || exit 1 - HOME=/tmp/npmuserhome - export HOME log_info 'Starting frontend ...' - s6-setuidgid npmuser yarn install - exec s6-setuidgid npmuser yarn start + s6-setuidgid "$PUID:$PGID" yarn install + exec s6-setuidgid "$PUID:$PGID" yarn start else exit 0 fi diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run index fa8c1fc..1f81e4c 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run @@ -5,5 +5,9 @@ set -e . /bin/common.sh +if [ "$(is_true "$DEBUG")" = '1' ]; then + set -x +fi + log_info 'Starting nginx ...' -exec s6-setuidgid npmuser nginx +exec s6-setuidgid "$PUID:$PGID" nginx diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh index e0b7eed..c392a0d 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh @@ -9,7 +9,11 @@ if [ "$(id -u)" != "0" ]; then log_fatal "This docker container must be run as root, do not specify a user.\nYou can specify PUID and PGID env vars to run processes as that user and group after initialization." fi -. /etc/s6-overlay/s6-rc.d/prepare/10-npmuser.sh +if [ "$(is_true "$DEBUG")" = '1' ]; then + set -x +fi + +. /etc/s6-overlay/s6-rc.d/prepare/10-usergroup.sh . /etc/s6-overlay/s6-rc.d/prepare/20-paths.sh . /etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh . /etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/10-usergroup.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/10-usergroup.sh new file mode 100755 index 0000000..ea10019 --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/10-usergroup.sh @@ -0,0 +1,40 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +set -e + +log_info "Configuring $NPMUSER user ..." + +if id -u "$NPMUSER" 2>/dev/null; then + # user already exists + usermod -u "$PUID" "$NPMUSER" +else + # Add user + useradd -o -u "$PUID" -U -d "$NPMHOME" -s /bin/false "$NPMUSER" +fi + +log_info "Configuring $NPMGROUP group ..." +if [ "$(get_group_id "$NPMGROUP")" = '' ]; then + # Add group. This will not set the id properly if it's already taken + groupadd -f -g "$PGID" "$NPMGROUP" +else + groupmod -o -g "$PGID" "$NPMGROUP" +fi + +# Set the group ID and check it +groupmod -o -g "$PGID" "$NPMGROUP" +if [ "$(get_group_id "$NPMGROUP")" != "$PGID" ]; then + echo "ERROR: Unable to set group id properly" + exit 1 +fi + +# Set the group against the user and check it +usermod -G "$PGID" "$NPMGROUP" +if [ "$(id -g "$NPMUSER")" != "$PGID" ] ; then + echo "ERROR: Unable to set group against the user properly" + exit 1 +fi + +# Home for user +mkdir -p "$NPMHOME" +chown -R "$PUID:$PGID" "$NPMHOME" diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/20-paths.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/20-paths.sh index adacfde..0be2af7 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/20-paths.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/20-paths.sh @@ -11,15 +11,17 @@ if [ ! -d '/data' ]; then fi # Create required folders -mkdir -p /tmp/nginx/body \ +mkdir -p \ + /data/logs \ + /data/nginx \ /run/nginx \ + /tmp/nginx/body \ /var/log/nginx \ /var/lib/nginx/cache/public \ /var/lib/nginx/cache/private \ - /var/cache/nginx/proxy_temp \ - /data/logs \ - /data/nginx + /var/cache/nginx/proxy_temp touch /var/log/nginx/error.log || true chmod 777 /var/log/nginx/error.log || true chmod -R 777 /var/cache/nginx || true +chmod 644 /etc/logrotate.d/nginx-proxy-manager diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh index 4a26406..4a02b5f 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh @@ -8,15 +8,16 @@ log_info 'Setting ownership ...' # root chown root /tmp/nginx -# npmuser -chown -R "$PUID:$PGID" /data \ - /run/nginx \ - /tmp/nginx \ - /var/cache/nginx \ - /var/lib/nginx \ - /var/log/nginx +# npm user and group +chown -R "$PUID:$PGID" /data +chown -R "$PUID:$PGID" /run/nginx +chown -R "$PUID:$PGID" /tmp/nginx +chown -R "$PUID:$PGID" /var/cache/nginx +chown -R "$PUID:$PGID" /var/lib/logrotate +chown -R "$PUID:$PGID" /var/lib/nginx +chown -R "$PUID:$PGID" /var/log/nginx # Don't chown entire /etc/nginx folder as this causes crashes on some systems -chown -R "$PUID:$PGID" /etc/nginx/nginx \ - /etc/nginx/nginx.conf \ - /etc/nginx/conf.d +chown -R "$PUID:$PGID" /etc/nginx/nginx +chown -R "$PUID:$PGID" /etc/nginx/nginx.conf +chown -R "$PUID:$PGID" /etc/nginx/conf.d diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh index 9fb4307..419c93b 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh @@ -9,7 +9,7 @@ DISABLE_IPV6=$(echo "${DISABLE_IPV6:-}" | tr '[:upper:]' '[:lower:]') # Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]` # thanks @tfmm -if [ "$(disable_ipv6)" == '1' ]; then +if [ "$(is_true "$DISABLE_IPV6")" = '1' ]; then echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) ipv6=off valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf else echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh index e018889..54339f3 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh @@ -1,8 +1,11 @@ -#!/bin/bash +#!/command/with-contenv bash +# shellcheck shell=bash # This command reads the `DISABLE_IPV6` env var and will either enable # or disable ipv6 in all nginx configs based on this setting. +set -e + log_info 'IPv6 ...' # Lowercase @@ -12,13 +15,13 @@ process_folder () { FILES=$(find "$1" -type f -name "*.conf") SED_REGEX= - if [ "$(disable_ipv6)" == '1' ]; then + if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ]; then # IPV6 is disabled - echo "❯ Disabling IPV6 in hosts in: $1" + echo "Disabling IPV6 in hosts in: $1" SED_REGEX='s/^([^#]*)listen \[::\]/\1#listen [::]/g' else # IPV6 is enabled - echo "❯ Enabling IPV6 in hosts in: $1" + echo "Enabling IPV6 in hosts in: $1" SED_REGEX='s/^(\s*)#listen \[::\]/\1listen [::]/g' fi @@ -28,7 +31,7 @@ process_folder () { sed -E -i "$SED_REGEX" "$FILE" || true done - # ensure the files are still owned by the npmuser + # ensure the files are still owned by the npm user chown -R "$PUID:$PGID" "$1" } diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/60-fail2ban.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/60-fail2ban.sh index cf99490..70071f1 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/60-fail2ban.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/60-fail2ban.sh @@ -3,11 +3,11 @@ set -e -log_info 'fail2ban ...' +log_info 'Fail2ban configuration ...' mkdir -p /fail2ban/{action.d,filter.d,jail.d,log} chown -R "$PUID:$PGID" /fail2ban -mkdir -p /var/run/fail2ban \ - /data/logs/fail2ban +mkdir -p /var/run/fail2ban +mkdir -p /data/logs/fail2ban chown nobody:nogroup /data/logs/fail2ban chmod 02755 /data/logs/fail2ban diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/90-banner.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/90-banner.sh index 7991ddf..4e69c0f 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/90-banner.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/90-banner.sh @@ -2,6 +2,9 @@ # shellcheck shell=bash set -e +set +x + +. /etc/os-release echo " ------------------------------------- @@ -11,7 +14,11 @@ echo " | |\ | __/| | | | |_| \_|_| |_| |_| ------------------------------------- -User ID: $PUID -Group ID: $PGID +Version: ${NPM_BUILD_VERSION:-3.0.0-dev} (${NPM_BUILD_COMMIT:-dev}) ${NPM_BUILD_DATE:-0000-00-00} +User: $NPMUSER PUID:$PUID ID:$(id -u "$NPMUSER") GROUP:$(id -g "$NPMUSER") +Group: $NPMGROUP PGID:$PGID ID:$(get_group_id "$NPMGROUP") +OpenResty: ${OPENRESTY_VERSION:-unknown} +Debian: ${VERSION_ID:-unknown} +Kernel: $(uname -r) ------------------------------------- " diff --git a/scripts/install-s6 b/scripts/install-s6 index 5a5a9c9..2922735 100755 --- a/scripts/install-s6 +++ b/scripts/install-s6 @@ -8,8 +8,8 @@ BLUE='\E[1;34m' GREEN='\E[1;32m' RESET='\E[0m' -S6_OVERLAY_VERSION=3.1.4.1 -TARGETPLATFORM=${1:unspecified} +S6_OVERLAY_VERSION=3.1.5.0 +TARGETPLATFORM=${1:-linux/amd64} # Determine the correct binary file for the architecture given case $TARGETPLATFORM in