Update the webmail images:

Roundcube
  - Switch to base image (alpine)
  - Switch to php-fpm
SnappyMail
  - Switch to base image
  - Upgrade php7 to php8.
main
Dimitri Huisman 2 years ago
parent 745c211c4a
commit 92f270c94e
No known key found for this signature in database

@ -174,12 +174,18 @@ target "smtp" {
target "snappymail" {
inherits = ["defaults"]
context = "webmails/snappymail/"
contexts = {
base = "target:base"
}
tags = tag("snappymail")
}
target "roundcube" {
inherits = ["defaults"]
context = "webmails/roundcube/"
contexts = {
base = "target:base"
}
tags = tag("roundcube")
}

@ -0,0 +1,7 @@
Update the webmail images.
Roundcube
- Switch to base image (alpine)
- Switch to php-fpm
SnappyMail
- Switch to base image
- Upgrade php7 to php8.

@ -1,65 +1,49 @@
FROM php:8.0-apache
# syntax=docker/dockerfile-upstream:1.4.3
#roundcube image
FROM base
ARG VERSION
ENV TZ Etc/UTC
LABEL version=$VERSION
RUN set -eu \
&& apt-get update \
&& echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \
&& apt-get install -y --no-install-recommends \
python3 curl python3-pip git python3-multidict \
python3-jinja2 gpg gpg-agent tzdata \
&& pip3 install socrate \
&& echo date.timezone=UTC > /usr/local/etc/php/conf.d/timezone.ini \
&& echo "ServerSignature Off\nServerName roundcube" >> /etc/apache2/apache2.conf \
&& sed -i '/CustomLog.*combined$/d' /etc/apache2/sites-available/000-default.conf \
\
&& mark="$(apt-mark showmanual)" \
&& apt-get install -y --no-install-recommends \
libfreetype6-dev libicu-dev libjpeg62-turbo-dev libldap2-dev libmagickwand-dev \
libpng-dev libpq-dev libsqlite3-dev libzip-dev libpspell-dev libonig-dev \
&& ln -s php.ini-production /usr/local/etc/php/php.ini \
&& docker-php-ext-configure gd --with-jpeg --with-freetype \
&& docker-php-ext-install exif gd intl zip pspell pdo_mysql pdo_pgsql pdo_sqlite \
&& pecl install imagick \
&& docker-php-ext-enable imagick opcache \
&& apt-mark auto '.*' >/dev/null \
&& apt-mark manual ${mark} >/dev/null \
&& ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so | awk '/=>/ { print $3 }' | sort -u | \
xargs -r dpkg-query -S | cut -d: -f1 | sort -u | xargs -r apt-mark manual >/dev/null \
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
&& rm -rf /var/lib/apt/lists
RUN apk add --no-cache \
nginx gpg gpg-agent \
php8 php8-fpm php8-mbstring php8-zip php8-xml php8-simplexml \
php8-dom php8-curl php8-exif gd php8-gd php8-iconv php8-intl php8-openssl \
php8-pdo_sqlite php8-pdo_mysql php8-pdo_pgsql php8-pdo php8-sodium libsodium php8-tidy php8-pecl-uuid \
php8-pspell php8-pecl-imagick php8-opcache php8-session php8-sockets php8-fileinfo \
&& rm /etc/nginx/http.d/default.conf \
&& rm /etc/php8/php-fpm.d/www.conf \
&& mkdir -p /run/nginx \
&& mkdir -p /conf
ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.3/roundcubemail-1.5.3-complete.tar.gz
ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.4.2/carddav-v4.4.2.tar.gz
ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.4.3/carddav-v4.4.3.tar.gz
RUN set -eu \
&& rm -rf /var/www/html/ \
&& cd /var/www \
RUN \
cd /var/www \
&& curl -sL ${ROUNDCUBE_URL} | tar xz \
&& curl -sL ${CARDDAV_URL} | tar xz \
&& mv roundcubemail-* html \
&& mv carddav html/plugins/ \
&& cd html \
&& mv roundcubemail-* webmail \
&& mkdir -p /var/www/webmail/config \
&& mv carddav webmail/plugins/ \
&& cd webmail \
&& rm -rf CHANGELOG.md SECURITY.md INSTALL LICENSE README.md UPGRADING composer.json-dist installer composer.* \
&& ln -sf index.php /var/www/html/sso.php \
&& ln -sf /dev/stderr /var/www/html/logs/errors.log \
&& chown -R root:root . \
&& chown www-data:www-data logs temp \
&& chmod -R a+rX . \
&& a2enmod rewrite deflate expires headers \
&& echo date.timezone=${TZ} > /usr/local/etc/php/conf.d/timezone.ini \
&& ln -sf index.php /var/www/webmail/sso.php \
&& chmod -R u+w,a+rX /var/www/webmail \
&& chown -R nginx:nginx /var/www/webmail \
&& rm -rf plugins/{autologon,example_addressbook,http_authentication,krb_authentication,new_user_identity,password,redundant_attachments,squirrelmail_usercopy,userinfo,virtuser_file,virtuser_query}
# enable database_attachments (and memcache?)
COPY mailu.php /var/www/html/plugins/mailu/mailu.php
COPY php.ini /
COPY config.inc.php /
# nginx / PHP config files
COPY config/nginx-roundcube.conf /conf/nginx-roundcube.conf
COPY config/php-roundcube.conf /etc/php8/php-fpm.d/roundcube.conf
COPY config/php.ini /conf/php.ini
COPY config/config.inc.php /conf/config.inc.php
COPY login/mailu.php /var/www/webmail/plugins/mailu/mailu.php
COPY config/config.inc.carddav.php /var/www/webmail/plugins/carddav/config.inc.php
COPY start.py /
COPY config.inc.carddav.php /var/www/html/plugins/carddav/config.inc.php
EXPOSE 80/tcp
VOLUME /data
@ -67,6 +51,6 @@ VOLUME /overrides
CMD /start.py
HEALTHCHECK CMD curl -f -L -H 'User-Agent: health' http://localhost/ || exit 1
HEALTHCHECK CMD curl -f -L http://localhost/ping || exit 1
RUN echo $VERSION >> /version

@ -16,20 +16,23 @@ $config['spellcheck_engine'] = 'pspell';
$config['session_lifetime'] = {{ SESSION_TIMEOUT_MINUTES | int }};
// Mail servers
$config['default_host'] = '{{ FRONT_ADDRESS or "front" }}';
$config['default_port'] = 10143;
$config['smtp_server'] = '{{ FRONT_ADDRESS or "front" }}';
$config['smtp_port'] = 10025;
$config['imap_host'] = '{{ FRONT_ADDRESS or "front" }}:10143';
$config['smtp_host'] = '{{ FRONT_ADDRESS or "front" }}:10025';
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
#old deprecated settings will be replaced from roundcube 1.6.
$config['smtp_server'] = '{{ FRONT_ADDRESS or "front" }}';
$config['smtp_port'] = '10025';
$config['default_host'] = '{{ FRONT_ADDRESS or "front" }}';
$config['default_port'] = '10143';
// Sieve script management
$config['managesieve_host'] = '{{ IMAP_ADDRESS or "imap" }}';
$config['managesieve_usetls'] = false;
// We access the IMAP and SMTP servers locally with internal names, SSL
// will obviously fail but this sounds better than allowing insecure login
// from the outer world
// from the outter world
$ssl_no_check = array(
'ssl' => array(
'verify_peer' => false,

@ -0,0 +1,62 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/webmail;
include /etc/nginx/mime.types;
# /dev/stdout (Default), <path>, off
access_log off;
# /dev/stderr (Default), <path>, debug, info, notice, warn, error, crit, alert, emerg
error_log /dev/stderr notice;
index index.php;
# set maximum body size to configured limit
client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
location / {
try_files $uri $uri/ /index.php$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
include /etc/nginx/fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_keep_conn on;
fastcgi_pass unix:/var/run/php8-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
{% if WEB_WEBMAIL == '/' %}
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
{% else %}
fastcgi_param SCRIPT_NAME {{WEB_WEBMAIL}}/$fastcgi_script_name;
{% endif %}
}
location ~ /\. {
deny all;
}
location ^~ /data {
deny all;
}
location = /ping {
allow 127.0.0.1;
deny all;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php8-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}

@ -0,0 +1,118 @@
; Start a new pool named 'roundcube'.
; the variable $pool can be used in any directive and will be replaced by the
; pool name ('roundcube' here)
[roundcube]
; Redirect worker stdout and stderr into main error log. If not set, stdout and
; stderr will be redirected to /dev/null according to FastCGI specs.
; Default value: no.
catch_workers_output = 1
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = nginx
group = nginx
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
; a specific port;
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses
; (IPv6 and IPv4-mapped) on a specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /var/run/php8-fpm.sock
; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server. Many
; BSD-derived systems allow connections regardless of permissions.
; Default Values: user and group are set as the running user
; mode is set to 0660
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
; Choose how the process manager will control the number of child processes.
; Possible Values:
; static - a fixed number (pm.max_children) of child processes;
; dynamic - the number of child processes are set dynamically based on the
; following directives. With this process management, there will be
; always at least 1 children.
; pm.max_children - the maximum number of children that can
; be alive at the same time.
; pm.start_servers - the number of children created on startup.
; pm.min_spare_servers - the minimum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is less than this
; number then some children will be created.
; pm.max_spare_servers - the maximum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is greater than this
; number then some children will be killed.
; ondemand - no children are created at startup. Children will be forked when
; new requests will connect. The following parameter are used:
; pm.max_children - the maximum number of children that
; can be alive at the same time.
; pm.process_idle_timeout - The number of seconds after which
; an idle process will be killed.
; Note: This value is mandatory.
pm = ondemand
; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 5
; The number of child processes created on startup.
; Note: Used only when pm is set to 'dynamic'
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
; pm.start_servers = 2
; The desired minimum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
; pm.min_spare_servers = 1
; The desired maximum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
; pm.max_spare_servers = 3
; This sets the maximum time in seconds a script is allowed to run before it is
; terminated by the parser. This helps prevent poorly written scripts from tying up
; the server. The default setting is 30s.
; Note: Used only when pm is set to 'ondemand'
pm.process_idle_timeout = 10s
; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries. For endless
; request processing specify '0'.
; Equivalent to PHP_FCGI_MAX_REQUESTS. Default value: 0.
; Noted: Used only when pm is set to 'ondemand'
pm.max_requests = 200
; The ping URI to call the monitoring page of FPM. If this value is not set, no
; URI will be recognized as a ping page. This could be used to test from outside
; that FPM is alive and responding, or to
; - create a graph of FPM availability (rrd or such);
; - remove a server from a group if it is not responding (load balancing);
; - trigger alerts for the operating team (24/7).
; Note: The value must start with a leading slash (/). The value can be
; anything, but it may not be a good idea to use the .php extension or it
; may conflict with a real PHP file.
; Default Value: not set
ping.path = /ping
; This directive may be used to customize the response of a ping request. The
; response is formatted as text/plain with a 200 response code.
; Default Value: pong
;ping.response = pong

@ -2,3 +2,7 @@ expose_php=Off
date.timezone={{ TZ }}
upload_max_filesize = {{ MAX_FILESIZE }}M
post_max_size = {{ MAX_FILESIZE }}M
suhosin.session.encrypt=Off
session.auto_start=Off
mbstring.func_overload=Off
file_uploads=On

@ -1,2 +0,0 @@
#!/bin/sh
SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 2>/dev/null | grep -qFx pong

@ -1,12 +1,13 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import os
import logging
import sys
from socrate import conf
import subprocess
import hmac
from socrate import conf
env = os.environ
logging.basicConfig(stream=sys.stderr, level=env.get("LOG_LEVEL", "WARNING"))
@ -51,7 +52,7 @@ context['SECRET_KEY'] = hmac.new(bytearray(secret_key, 'utf-8'), bytearray('ROUN
# roundcube plugins
# (using "dict" because it is ordered and "set" is not)
plugins = dict((p, None) for p in env.get("ROUNDCUBE_PLUGINS", "").replace(" ", "").split(",") if p and os.path.isdir(os.path.join("/var/www/html/plugins", p)))
plugins = dict((p, None) for p in env.get("ROUNDCUBE_PLUGINS", "").replace(" ", "").split(",") if p and os.path.isdir(os.path.join("/var/www/webmail/plugins", p)))
if plugins:
plugins["mailu"] = None
else:
@ -60,52 +61,56 @@ else:
context["PLUGINS"] = ",".join(f"'{p}'" for p in plugins)
# add overrides
context["INCLUDES"] = sorted(inc for inc in os.listdir("/overrides") if inc.endswith((".inc", ".inc.php"))) if os.path.isdir("/overrides") else []
context["INCLUDES"] = sorted(inc for inc in os.listdir("/overrides") if inc.endswith(".inc")) if os.path.isdir("/overrides") else []
# calculate variables for config file
context["SESSION_TIMEOUT_MINUTES"] = max(int(env.get("SESSION_TIMEOUT", "3600")) // 60, 1)
# create config files
conf.jinja("/php.ini", context, "/usr/local/etc/php/conf.d/roundcube.ini")
conf.jinja("/config.inc.php", context, "/var/www/html/config/config.inc.php")
conf.jinja("/conf/php.ini", context, "/etc/php8/php.ini")
conf.jinja("/conf/config.inc.php", context, "/var/www/webmail/config/config.inc.php")
# create dirs
os.system("mkdir -p /data/gpg")
# disable access log for VirtualHosts that don't define their own logfile
os.system("a2disconf other-vhosts-access-log")
print("Initializing database")
try:
result = subprocess.check_output(["/var/www/html/bin/initdb.sh", "--dir", "/var/www/html/SQL"],
result = subprocess.check_output(["/var/www/webmail/bin/initdb.sh", "--dir", "/var/www/webmail/SQL"],
stderr=subprocess.STDOUT)
print(result.decode())
except subprocess.CalledProcessError as exc:
err = exc.stdout.decode()
if "already exists" in err:
print("Already initialized")
print("Already initialzed")
else:
print(err)
exit(3)
print("Upgrading database")
try:
subprocess.check_call(["/var/www/html/bin/update.sh", "--version=?", "-y"], stderr=subprocess.STDOUT)
subprocess.check_call(["/var/www/webmail/bin/update.sh", "--version=?", "-y"], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
exit(4)
else:
print("Cleaning database")
try:
subprocess.check_call(["/var/www/html/bin/cleandb.sh"], stderr=subprocess.STDOUT)
subprocess.check_call(["/var/www/webmail/bin/cleandb.sh"], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
exit(5)
# setup permissions
os.system("chown -R www-data:www-data /data")
os.system("chown -R nginx:nginx /data")
os.system("chmod -R a+rX /var/www/webmail/")
# Configure nginx
conf.jinja("/conf/nginx-roundcube.conf", context, "/etc/nginx/http.d/roundcube.conf")
if os.path.exists("/var/run/nginx.pid"):
os.system("nginx -s reload")
# clean env
[env.pop(key, None) for key in env.keys() if key == "SECRET_KEY" or key.startswith("ROUNDCUBE_")]
# run apache
os.execve("/usr/local/bin/apache2-foreground", ["apache2-foreground"], env)
# run nginx
os.system("php-fpm8")
os.execv("/usr/sbin/nginx", ["nginx", "-g", "daemon off;"])

@ -1,26 +1,18 @@
ARG ARCH=""
# syntax=docker/dockerfile-upstream:1.4.3
#snappymail image
FROM base
# NOTE: only add file if building for arm
FROM ${ARCH}alpine:3.14
ARG VERSION
ONBUILD COPY --from=balenalib/rpi-alpine:3.14 /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static
ENV TZ Etc/UTC
LABEL version=$VERSION
# Shared later between dovecot postfix nginx rspamd snappymail and roundloop
RUN apk add --no-cache \
python3 py3-pip tzdata \
&& pip3 install socrate==0.2.0
# https://github.com/the-djmaze/snappymail/wiki/Installation-instructions#requirements
# SnappyMail:
# SnappyMail requires PHP 7.4 (or a newer version) with the following extensions:
#
# mbstring php7-mbstring
# Zlib built-in OR php7-zip????
# json php7-json
# json php7-json > php8-json is built-in php8 in alpine
# libxml php7-xml
# dom php7-dom
@ -44,18 +36,18 @@ RUN apk add --no-cache \
#php7-curl php7-iconv php7-json php7-xml php7-simplexml php7-dom php7-openssl php7-pdo php7-pdo_sqlite php7-mbstring \
RUN apk add --no-cache \
nginx curl \
php7 php7-fpm php7-mbstring php7-zip php7-json php7-xml php7-simplexml \
php7-dom php7-curl php7-exif gd php7-gd php7-iconv php7-intl php7-openssl \
php7-pdo_sqlite php7-pdo php7-sodium libsodium php7-tidy php7-pecl-uuid \
php8 php8-fpm php8-mbstring php8-zip php8-xml php8-simplexml \
php8-dom php8-curl php8-exif gd php8-gd php8-iconv php8-intl php8-openssl \
php8-pdo_sqlite php8-pdo php8-sodium libsodium php8-tidy php8-pecl-uuid \
&& rm /etc/nginx/http.d/default.conf \
&& rm /etc/php7/php-fpm.d/www.conf \
&& rm /etc/php8/php-fpm.d/www.conf \
&& mkdir -p /run/nginx \
&& mkdir -p /var/www/webmail \
&& mkdir -p /config
# nginx / PHP config files
COPY config/nginx-snappymail.conf /config/nginx-snappymail.conf
COPY config/php-snappymail.conf /etc/php7/php-fpm.d/snappymail.conf
COPY config/php-snappymail.conf /etc/php8/php-fpm.d/snappymail.conf
# Parsed and moved at startup
COPY defaults/php.ini /defaults/php.ini
@ -74,7 +66,7 @@ RUN cd /var/www/webmail \
COPY login/include.php /var/www/webmail/include.php
COPY login/sso.php /var/www/webmail/sso.php
COPY start.py /start.py
COPY start.py /
COPY config.py /config.py
EXPOSE 80/tcp

@ -1,8 +1,9 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import os
import logging as log
import sys
from socrate import system, conf
args = os.environ.copy()

@ -33,7 +33,7 @@ server {
fastcgi_keep_conn on;
fastcgi_pass unix:/var/run/php7-fpm.sock;
fastcgi_pass unix:/var/run/php8-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
{% if WEB_WEBMAIL == '/' %}
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
@ -56,7 +56,7 @@ server {
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php7-fpm.sock;
fastcgi_pass unix:/var/run/php8-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}

@ -24,7 +24,7 @@ group = nginx
; (IPv6 and IPv4-mapped) on a specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /var/run/php7-fpm.sock
listen = /var/run/php8-fpm.sock
; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server. Many

@ -1,10 +1,11 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import os
import shutil
import logging as log
import sys
import subprocess
from socrate import system, conf
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
@ -22,9 +23,9 @@ os.makedirs(base + "configs", exist_ok=True)
conf.jinja("/defaults/default.ini", os.environ, "/data/_data_/_default_/domains/default.ini")
conf.jinja("/defaults/application.ini", os.environ, "/data/_data_/_default_/configs/application.ini")
conf.jinja("/defaults/php.ini", os.environ, "/etc/php7/php.ini")
conf.jinja("/defaults/php.ini", os.environ, "/etc/php8/php.ini")
# Start the fastcgi process manager now that config files have been adjusted
os.system("php-fpm7")
os.system("php-fpm8")
os.system("chown -R nginx:nginx /data")
os.system("chmod -R a+rX /var/www/webmail/")

Loading…
Cancel
Save