diff --git a/.env b/.env new file mode 100644 index 0000000000..30a916fe99 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +ZNUNY_MARIADB_VOL=/home/jay/dockervol/znuny/mariadb +external_port=80 +DB_HOST=znuny-db +DB_NAME=znunycustom +DB_USER=znunycustomuser +DB_USER_PASS=znunycustompw +ZNUNY_CUSTOM_HTDOCS=/home/jay/dockervol/znuny/htdocs diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..7a781caad3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,73 @@ +networks: + znuny-net: + driver: bridge + +volumes: + MariaDBVol: + ZnunyPersistent: + ZnunyVar: + ZnunyArticle: + ZnunyHTDocs: + +services: + znuny-daemon: + build: + context: . + dockerfile: ./dockerfiles/daemon + container_name: znuny_daemon + networks: + - znuny-net + environment: + DB_HOST: ${DB_HOST:-znuny-db} + DB_NAME: ${DB_NAME:-znuny} + DB_USER: ${DB_USER:-znuny} + DB_USER_PASS: ${DB_USER_PASS:-some-pass} + restart: unless-stopped + depends_on: + - znuny-db + volumes: + - ZnunyVar:/opt/znuny/var/log + - ZnunyArticle:/opt/znuny/var/article + - ZnunyHTDocs:/opt/znuny/var/httpd/htdocs/custom + - ZnunyPersistent:/persistent + + znuny-httpd: + build: + context: . + dockerfile: ./dockerfiles/apache + container_name: znuny_httpd + ports: + - "${external_port:-80}:80" + depends_on: + - znuny-daemon + networks: + - znuny-net + restart: unless-stopped + volumes: + - ZnunyVar:/opt/znuny/var/log + - ZnunyArticle:/opt/znuny/var/article + - ZnunyHTDocs:/opt/znuny/var/httpd/htdocs/custom + - ZnunyPersistent:/persistent + + znuny-db: + image: mariadb:${MARIADB_VERSION:-11.4.7} + container_name: znuny_db + mem_limit: ${ZNUNY_DB_MEMLIMIT:-2048m} + environment: + MYSQL_ROOT_PASSWORD: ${ROOT_PASS:-root-pass} + MYSQL_DATABASE: ${DB_NAME:-znuny} + MYSQL_USER: ${DB_USER:-znuny} + MYSQL_PASSWORD: ${DB_USER_PASS:-some-pass} + volumes: + - MariaDBVol:/var/lib/mysql + restart: unless-stopped + ports: + - "${DB_PORT:-3306}:3306" + networks: + - znuny-net + command: [ + "--max_allowed_packet=256M", + "--innodb_log_file_size=512M" + ] + labels: + org.label-schema.group: "znuny" \ No newline at end of file diff --git a/docker-specific/apache_starter.sh b/docker-specific/apache_starter.sh new file mode 100644 index 0000000000..fcf069a7f8 --- /dev/null +++ b/docker-specific/apache_starter.sh @@ -0,0 +1,2 @@ +#!/bin/bash +apache2 -DFOREGROUND \ No newline at end of file diff --git a/docker-specific/watchdog.sh b/docker-specific/watchdog.sh new file mode 100644 index 0000000000..93960a44cc --- /dev/null +++ b/docker-specific/watchdog.sh @@ -0,0 +1,43 @@ +#!/bin/sh +set -eu + +ZNUNY_HOME="/opt/znuny" +cd "$ZNUNY_HOME" + +echo 'Checking modules...' +$ZNUNY_HOME/bin/znuny.CheckModules.pl --all + +echo 'Starting Watchdog.' + +CHECK_INTERVAL=30 # seconds +MAX_FAILS=10 # 10 × 30s = 5 minutes + +FAILS=0 +DAEMON="/opt/znuny-dev/bin/znuny.Daemon.pl" + +term_handler() { + echo "Received termination signal, stopping Znuny" + perl "$DAEMON" stop || true + exit 0 +} + +trap term_handler INT TERM + +echo "Znuny supervisor started" +perl "$DAEMON" start || true + +while true; do + if perl "$DAEMON" status | grep -q "Daemon running"; then + FAILS=0 + else + FAILS=$((FAILS + 1)) + echo "Znuny not running ($FAILS/$MAX_FAILS)" + fi + + if [ "$FAILS" -ge "$MAX_FAILS" ]; then + echo "Znuny down for 5 minutes — exiting container" + exit 1 + fi + + sleep "$CHECK_INTERVAL" +done diff --git a/dockerfiles/apache b/dockerfiles/apache new file mode 100644 index 0000000000..1b09c1cfcc --- /dev/null +++ b/dockerfiles/apache @@ -0,0 +1,108 @@ +# Dockerfile.httpd +FROM ubuntu:jammy + +ARG ZNUNY_VERSION=dev +ARG ZNUNY_USER=znuny +ENV ZNUNY_HOME=/opt/znuny-${ZNUNY_VERSION} \ + PATH=$PATH:/opt/znuny-${ZNUNY_VERSION}/bin +ARG APACHE_USER=www-data + +# Install Apache and minimal packages +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + apache2 libapache2-mod-perl2 curl unzip vim \ + libdbi-perl \ + libdbd-mysql-perl \ + libapache-dbi-perl && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN apt-get update && \ + apt-get install -y \ + libdbi-perl \ + libdbd-mysql-perl \ + libtimedate-perl \ + libnet-dns-perl \ + libnet-ldap-perl \ + libio-socket-ssl-perl \ + libpdf-api2-perl \ + libsoap-lite-perl \ + libtext-csv-xs-perl \ + libjson-xs-perl \ + libapache-dbi-perl \ + libxml-libxml-perl \ + libxml-libxslt-perl \ + libyaml-perl \ + libarchive-zip-perl \ + libcrypt-eksblowfish-perl \ + libencode-hanextra-perl \ + libmail-imapclient-perl \ + libtemplate-perl \ + libdatetime-perl \ + libdatetime-timezone-perl \ + libdatetime-locale-perl \ + libmoo-perl \ + libyaml-libyaml-perl \ + libjavascript-minifier-xs-perl \ + libcss-minifier-xs-perl \ + libauthen-sasl-perl \ + libauthen-ntlm-perl \ + libdbd-pg-perl \ + libcrypt-jwt-perl \ + libcrypt-openssl-x509-perl \ + libhash-merge-perl \ + libical-parser-perl \ + dos2unix \ + gosu \ + libspreadsheet-xlsx-perl \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Inject project files for setup and clean up +RUN mkdir ${ZNUNY_HOME} +COPY ./bin ${ZNUNY_HOME}/bin +COPY ./Custom ${ZNUNY_HOME}/Custom +COPY ./doc ${ZNUNY_HOME}/doc +COPY ./Kernel ${ZNUNY_HOME}/Kernel +COPY ./scripts ${ZNUNY_HOME}/scripts +COPY ./var ${ZNUNY_HOME}/var +COPY ./AUTHORS.md ./CHANGES.md ./CONTRIBUTING.md ./COPYING ./INSTALL.md ./COPYING-Third-Party ./RELEASE ./SECURITY.md ./UPDATING.md ${ZNUNY_HOME}/ + +RUN ln -s ${ZNUNY_HOME} /opt/znuny + +RUN find ${ZNUNY_HOME} -type f -exec dos2unix {} + +RUN mkdir /persistent && cp /opt/znuny/Kernel/Config.pm.dist /persistent/Config.pm && chown -R www-data:www-data /persistent + +# Apache configuration +RUN a2dismod mpm_event && \ + a2enmod mpm_prefork perl headers deflate filter cgi rewrite && \ + ln -s ${ZNUNY_HOME}/scripts/apache2-httpd.include.conf /etc/apache2/conf-available/zzz_znuny.conf && \ + a2enconf zzz_znuny && \ + echo "RedirectMatch ^/$ /znuny/index.pl" >> /etc/apache2/apache2.conf + +ENV APACHE_RUN_USER=${APACHE_USER} \ + APACHE_RUN_GROUP=${APACHE_USER} \ + APACHE_RUN_DIR=/var/run/apache2 \ + APACHE_LOCK_DIR=/var/lock/apache2 \ + APACHE_LOG_DIR=/var/log/apache2 \ + APACHE_PID_FILE=/var/run/apache2/apache2.pid + +RUN mkdir -p /var/run/apache2 /var/lock/apache2 /var/log/apache2 && \ + chown -R ${APACHE_USER}:${APACHE_USER} /var/run/apache2 /var/lock/apache2 /var/log/apache2 + +# Expose HTTP port +EXPOSE 80 + +# Create Znuny user and set permissions +RUN useradd -d ${ZNUNY_HOME} -c "Znuny user" -g www-data -s /bin/bash -M -N ${ZNUNY_USER} +WORKDIR ${ZNUNY_HOME} +RUN bin/znuny.SetPermissions.pl --znuny-user ${ZNUNY_USER} + +# Setup Entry +COPY ./entrypoints/apache.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh +COPY ./docker-specific/apache_starter.sh /usr/local/bin/apache_starter.sh +RUN chmod +x /usr/local/bin/apache_starter.sh +RUN chown www-data: /usr/local/bin/apache_starter.sh + +USER root +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] +CMD ["/usr/local/bin/apache_starter.sh"] \ No newline at end of file diff --git a/dockerfiles/daemon b/dockerfiles/daemon new file mode 100644 index 0000000000..93139a4069 --- /dev/null +++ b/dockerfiles/daemon @@ -0,0 +1,75 @@ +# Dockerfile.daemon +FROM ubuntu:jammy + +ARG ZNUNY_VERSION=dev +ARG ZNUNY_USER=znuny +ENV ZNUNY_HOME=/opt/znuny-${ZNUNY_VERSION} \ + PATH=$PATH:/opt/znuny-${ZNUNY_VERSION}/bin + +# Install required packages and Perl modules +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + wget mariadb-client cpanminus cron vim \ + libdbd-odbc-perl libapache2-mod-perl2 \ + libdbd-mysql-perl libtimedate-perl libnet-dns-perl libnet-ldap-perl \ + libio-socket-ssl-perl libpdf-api2-perl libsoap-lite-perl \ + libtext-csv-xs-perl libjson-xs-perl libapache-dbi-perl \ + libxml-libxml-perl libxml-libxslt-perl libyaml-perl \ + libarchive-zip-perl libcrypt-eksblowfish-perl libencode-hanextra-perl \ + libmail-imapclient-perl libtemplate-perl libdatetime-perl libmoo-perl \ + bash-completion libyaml-libyaml-perl libjavascript-minifier-xs-perl \ + libcss-minifier-xs-perl libauthen-sasl-perl libauthen-ntlm-perl \ + libdbd-pg-perl libcrypt-jwt-perl libcrypt-openssl-x509-perl \ + libhash-merge-perl libical-parser-perl libspreadsheet-xlsx-perl \ + nullmailer uuid-dev build-essential curl unzip dos2unix gosu && \ + echo "smtp.unibas.ch" > /etc/nullmailer/remotes && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Setup Perl modules +RUN cpanm --notest --force Jq Data::UUID + + +# Inject project files for setup and clean up +RUN mkdir ${ZNUNY_HOME} +COPY ./bin ${ZNUNY_HOME}/bin +COPY ./Custom ${ZNUNY_HOME}/Custom +COPY ./doc ${ZNUNY_HOME}/doc +COPY ./Kernel ${ZNUNY_HOME}/Kernel +COPY ./scripts ${ZNUNY_HOME}/scripts +COPY ./var ${ZNUNY_HOME}/var +COPY ./AUTHORS.md ./CHANGES.md ./CONTRIBUTING.md ./COPYING ./INSTALL.md ./COPYING-Third-Party ./RELEASE ./SECURITY.md ./UPDATING.md ${ZNUNY_HOME}/ + +RUN ln -s ${ZNUNY_HOME} /opt/znuny + +WORKDIR ${ZNUNY_HOME} + +# Fixing DOS newlines to fit unix +RUN find ${ZNUNY_HOME} -type f -exec dos2unix {} + + + +# Create Znuny user and set permissions +RUN useradd -d ${ZNUNY_HOME} -c "Znuny user" -g www-data -s /bin/bash -M -N ${ZNUNY_USER} +RUN mkdir /persistent && cp /opt/znuny/Kernel/Config.pm.dist /persistent/Config.pm && chown -R www-data:www-data /persistent +RUN ln -s /persistent/Config.pm Kernel/Config.pm +RUN bin/znuny.SetPermissions.pl --znuny-user ${ZNUNY_USER} + + +# Configure cron jobs +RUN su - ${ZNUNY_USER} -c "cd ${ZNUNY_HOME}/var/cron && for f in *.dist; do cp \$f \$(basename \$f .dist); done" +RUN mkdir var/tmp && chown ${ZNUNY_USER}:www-data var/tmp +RUN chmod +x bin/Cron.sh +RUN bin/Cron.sh start ${ZNUNY_USER} + +# Setup Entrypoint +COPY ./entrypoints/daemon.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +# Watchdog Setup +COPY ./docker-specific/watchdog.sh /usr/local/bin/watchdog.sh +RUN chmod +x /usr/local/bin/watchdog.sh +RUN chown ${ZNUNY_USER}:www-data /usr/local/bin/watchdog.sh + +USER root + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] +CMD ["/usr/local/bin/watchdog.sh"] \ No newline at end of file diff --git a/entrypoints/apache.sh b/entrypoints/apache.sh new file mode 100644 index 0000000000..ea72657cae --- /dev/null +++ b/entrypoints/apache.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# You can do some boot checks, like initial setup steps here. +# Vars +external_port="${external_port:-80}" +PERSISTENT_CFG="/persistent/Config.pm" +ZNUNY_CFG="/opt/znuny/Kernel/Config.pm" + +# Welcome message +echo Listening on port ${external_port} + + +# Setup persistence +if [ -f "$PERSISTENT_CFG" ]; then + echo "Using persistent Config.pm" +else + echo "Persistent Config.pm not found, seeding it" + cp "$ZNUNY_CFG" "$PERSISTENT_CFG" +fi +ln -sf "$PERSISTENT_CFG" "$ZNUNY_CFG" + +# Move to Main process +exec gosu www-data "$@" \ No newline at end of file diff --git a/entrypoints/daemon.sh b/entrypoints/daemon.sh new file mode 100644 index 0000000000..e6126e9da9 --- /dev/null +++ b/entrypoints/daemon.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +PERSISTENT_CFG="/persistent/Config.pm" +ZNUNY_CFG="/opt/znuny/Kernel/Config.pm" +ZNUNY_HOME="/opt/znuny" +DB_HOST="${DB_HOST:-127.0.0.1}" +DB_NAME="${DB_NAME:-znuny}" +DB_USER="${DB_USER:-znuny}" +DB_USER_PASS="${DB_USER_PASS:-some-pass}" + +service nullmailer start +service cron start + +if [ -f "$PERSISTENT_CFG" ]; then + echo "Using persistent Config.pm" +else + echo "Persistent Config.pm not found, seeding it" + cp "$ZNUNY_CFG" "$PERSISTENT_CFG" +fi +ln -sf "$PERSISTENT_CFG" "$ZNUNY_CFG" + +# Setup Config.pm +sed -i "s/\$Self->{DatabaseHost} = '127\.0\.0\.1';/\$Self->{DatabaseHost} = '$DB_HOST';/" $PERSISTENT_CFG +sed -i "s/\$Self->{Database} = 'znuny';/\$Self->{Database} = '$DB_NAME';/" $PERSISTENT_CFG +sed -i "s/\$Self->{DatabaseUser} = 'znuny';/\$Self->{DatabaseUser} = '$DB_USER';/" $PERSISTENT_CFG +sed -i "s/\$Self->{DatabasePw} = 'some-pass';/\$Self->{DatabasePw} = '$DB_USER_PASS';/" $PERSISTENT_CFG + +chown -R znuny:www-data /persistent/Config.pm +chmod -R 770 /persistent/Config.pm +cd "$ZNUNY_HOME" + +echo "For initial setup, visit http://hostname:port/znuny/installer.pl" +$ZNUNY_HOME/bin/znuny.SetPermissions.pl + +exec gosu znuny "$@" \ No newline at end of file