2295: Switch from Rainloop to SnappyMail r=mergify[bot] a=Diman0

## What type of PR?

Feature

## What does this PR do?
As discussed in the project meeting (#1582), we decided we want to switch from Rainloop to an alternative. Rainloop has multiple open security issues which were not patched for a long time. 

We decided to switch to SnappyMail because it is more secure and based on RainLoop. This means that users using RainLoop will still have a webmail that looks familiar for them.

This PR replaces RainLoop with SnappyMail.

### Related issue(s)
- #2215 
- #1582

## Prerequisites
Before we can consider review and merge, please make sure the following list is done and checked.
If an entry in not applicable, you can check it or remove it from the list.

- [x] In case of feature or enhancement: documentation updated accordingly
- [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file.


Co-authored-by: Dimitri Huisman <diman@huisman.xyz>
Co-authored-by: Florent Daigniere <nextgens@users.noreply.github.com>
master
bors[bot] 2 years ago committed by GitHub
commit 238daef6d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -110,7 +110,7 @@ jobs:
DOCKER_ORG: ${{ env.DOCKER_ORG }} DOCKER_ORG: ${{ env.DOCKER_ORG }}
run: docker-compose -f tests/build.yml build run: docker-compose -f tests/build.yml build
- name: Save all docker images - name: Save all docker images
run: docker save ${{ env.DOCKER_ORG }}/admin ${{ env.DOCKER_ORG }}/clamav ${{ env.DOCKER_ORG }}/docs ${{ env.DOCKER_ORG }}/dovecot ${{ env.DOCKER_ORG }}/fetchmail ${{ env.DOCKER_ORG }}/nginx ${{ env.DOCKER_ORG }}/none ${{ env.DOCKER_ORG }}/postfix ${{ env.DOCKER_ORG }}/radicale ${{ env.DOCKER_ORG }}/rainloop ${{ env.DOCKER_ORG }}/roundcube ${{ env.DOCKER_ORG }}/rspamd ${{ env.DOCKER_ORG }}/setup ${{ env.DOCKER_ORG }}/traefik-certdumper ${{ env.DOCKER_ORG }}/unbound -o /images/images.tar.gz run: docker save ${{ env.DOCKER_ORG }}/admin ${{ env.DOCKER_ORG }}/clamav ${{ env.DOCKER_ORG }}/docs ${{ env.DOCKER_ORG }}/dovecot ${{ env.DOCKER_ORG }}/fetchmail ${{ env.DOCKER_ORG }}/nginx ${{ env.DOCKER_ORG }}/none ${{ env.DOCKER_ORG }}/postfix ${{ env.DOCKER_ORG }}/radicale ${{ env.DOCKER_ORG }}/snappymail ${{ env.DOCKER_ORG }}/roundcube ${{ env.DOCKER_ORG }}/rspamd ${{ env.DOCKER_ORG }}/setup ${{ env.DOCKER_ORG }}/traefik-certdumper ${{ env.DOCKER_ORG }}/unbound -o /images/images.tar.gz
test-core: test-core:
name: Perform core tests name: Perform core tests
@ -328,8 +328,8 @@ jobs:
PINNED_MAILU_VERSION: ${{ env.PINNED_MAILU_VERSION }} PINNED_MAILU_VERSION: ${{ env.PINNED_MAILU_VERSION }}
DOCKER_ORG: ${{ env.DOCKER_ORG }} DOCKER_ORG: ${{ env.DOCKER_ORG }}
test-rainloop: test-snappymail:
name: Perform rainloop tests name: Perform snappymail tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- build - build
@ -393,8 +393,8 @@ jobs:
run: python3 -m pip install -r tests/requirements.txt run: python3 -m pip install -r tests/requirements.txt
- name: Copy all certs - name: Copy all certs
run: sudo -- sh -c 'mkdir -p /mailu && cp -r tests/certs /mailu && chmod 600 /mailu/certs/*' run: sudo -- sh -c 'mkdir -p /mailu && cp -r tests/certs /mailu && chmod 600 /mailu/certs/*'
- name: Test rainloop - name: Test snappymail
run: python tests/compose/test.py rainloop 2 run: python tests/compose/test.py snappymail 2
env: env:
MAILU_VERSION: ${{ env.MAILU_VERSION }} MAILU_VERSION: ${{ env.MAILU_VERSION }}
PINNED_MAILU_VERSION: ${{ env.PINNED_MAILU_VERSION }} PINNED_MAILU_VERSION: ${{ env.PINNED_MAILU_VERSION }}
@ -552,7 +552,7 @@ jobs:
- test-core - test-core
- test-fetchmail - test-fetchmail
- test-filters - test-filters
- test-rainloop - test-snappymail
- test-roundcube - test-roundcube
- test-webdav - test-webdav
steps: steps:

@ -11,7 +11,7 @@ RUN apk add --no-cache \
python3 py3-pip git bash py3-multidict py3-yarl tzdata \ python3 py3-pip git bash py3-multidict py3-yarl tzdata \
&& pip3 install --upgrade pip && pip3 install --upgrade pip
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube # Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, snappymail, roundcube
RUN pip3 install socrate==0.2.0 RUN pip3 install socrate==0.2.0
# Shared layer between dovecot and postfix # Shared layer between dovecot and postfix

@ -11,7 +11,7 @@ RUN apk add --no-cache \
python3 py3-pip git bash py3-multidict \ python3 py3-pip git bash py3-multidict \
&& pip3 install --upgrade pip && pip3 install --upgrade pip
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube # Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, snappymail, roundcube
RUN pip3 install socrate==0.2.0 RUN pip3 install socrate==0.2.0
# Image specific layers under this line # Image specific layers under this line

@ -12,7 +12,7 @@ RUN apk add --no-cache \
python3 py3-pip git bash py3-multidict py3-yarl tzdata \ python3 py3-pip git bash py3-multidict py3-yarl tzdata \
&& pip3 install --upgrade pip && pip3 install --upgrade pip
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube # Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, snappymail, roundcube
RUN pip3 install socrate==0.2.0 RUN pip3 install socrate==0.2.0
# Shared layer between dovecot and postfix # Shared layer between dovecot and postfix

@ -10,7 +10,7 @@ RUN apk add --no-cache \
python3 py3-pip git bash py3-multidict tzdata \ python3 py3-pip git bash py3-multidict tzdata \
&& pip3 install --upgrade pip && pip3 install --upgrade pip
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube # Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, snappymail, roundcube
RUN pip3 install socrate==0.2.0 RUN pip3 install socrate==0.2.0
# Image specific layers under this line # Image specific layers under this line

@ -39,16 +39,16 @@ Postfix configuration overrides.
RSpamD configuration overrides. RSpamD configuration overrides.
#### Rainloop #### Snappymail
- Old path: `/mailu/webmail/_data_/_default_/storage` (part of `/mailu/webmail` mountpoint, shared with Roundcube) - Old path: `/mailu/webmail/_data_/_default_/storage` (part of `/mailu/webmail` mountpoint, shared with Roundcube)
- New path: `/mailu/config/rainloop` - New path: `/mailu/config/snappymail`
User specific configs. The remaining files under the old `/mailu/webmail` don't need to be persistent. Except for `AddressBook.sqlite`, see `/mailu/data`. User specific configs. The remaining files under the old `/mailu/webmail` don't need to be persistent. Except for `AddressBook.sqlite`, see `/mailu/data`.
#### Roundcube #### Roundcube
- Old path: `/mailu/webmail/gpg` (part of `/mailu/webmail` mountpoint, shared with Rainloop) - Old path: `/mailu/webmail/gpg` (part of `/mailu/webmail` mountpoint, shared with Snappymail)
- New path: `/mailu/config/roundcube/gpg` - New path: `/mailu/config/roundcube/gpg`
User configured GPG keys. User configured GPG keys.
@ -108,10 +108,10 @@ This move is needed in order to be able to mount the directory without exposing
Storage of Bayes and Fuzzy learning SQLite databases and caches. As future optimization we should look into moving all this into Redis. Storage of Bayes and Fuzzy learning SQLite databases and caches. As future optimization we should look into moving all this into Redis.
#### Rainloop #### SnappyMail
- Old path: `/mailu/webmail/_data_/_default_/AddressBook.sqlite` (part of `/mailu/webmail` mountpoint, shared with Roundcube) - Old path: `/mailu/webmail/_data_/_default_/AddressBook.sqlite` (part of `/mailu/webmail` mountpoint, shared with Roundcube)
- New path: `/mailu/data/rainloop/AddressBook.sqlite` (mount on `rainloop` directory) - New path: `/mailu/data/snappymail/AddressBook.sqlite` (mount on `snappymail` directory)
Addressbook SQLite file. For future replicated deployments this might better be configured to use an external DB. Addressbook SQLite file. For future replicated deployments this might better be configured to use an external DB.
@ -119,7 +119,7 @@ For this modification, the `AddressBook.sqlite` will need to be moved to a diffe
#### Roundcube #### Roundcube
- Old path: `/mailu/webmail/roundcube.db` (part of `/mailu/webmail` mountpoint, shared with Rainloop) - Old path: `/mailu/webmail/roundcube.db` (part of `/mailu/webmail` mountpoint, shared with SnappyMail)
- New path: `/mailu/data/roundcube/roundcube.db` (mount on `roundcube` directory) - New path: `/mailu/data/roundcube/roundcube.db` (mount on `roundcube` directory)
User settings SQLite database file for roundcube. For future replicated deployments this might better be configured to use an external DB. User settings SQLite database file for roundcube. For future replicated deployments this might better be configured to use an external DB.
@ -163,7 +163,7 @@ The final layout of the Mailu filesystem will look like:
├── config ├── config
│   ├── dovecot │   ├── dovecot
│   ├── postfix │   ├── postfix
│   ├── rainloop │   ├── snappymail
│   ├── redis │   ├── redis
│   ├── roundcube │   ├── roundcube
│   │   └── gpg │   │   └── gpg
@ -173,7 +173,7 @@ The final layout of the Mailu filesystem will look like:
│   └── dkim │   └── dkim
├── data ├── data
│   ├── admin │   ├── admin
│   ├── rainloop │   ├── snappymail
│   ├── roundcube │   ├── roundcube
│   └── rspamd │   └── rspamd
├── local ├── local

@ -50,7 +50,7 @@ DISABLE_STATISTICS=False
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN=false ADMIN=false
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL=none WEBMAIL=none
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)

@ -11,7 +11,7 @@ RUN apk add --no-cache \
python3 py3-pip git bash py3-multidict tzdata \ python3 py3-pip git bash py3-multidict tzdata \
&& pip3 install --upgrade pip && pip3 install --upgrade pip
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube # Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, snappymail, roundcube
RUN pip3 install socrate==0.2.0 RUN pip3 install socrate==0.2.0
# Image specific layers under this line # Image specific layers under this line

@ -49,7 +49,7 @@ DISABLE_STATISTICS={{ disable_statistics or 'False' }}
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN={{ admin_enabled or 'false' }} ADMIN={{ admin_enabled or 'false' }}
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL={{ webmail_type }} WEBMAIL={{ webmail_type }}
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)

@ -10,13 +10,9 @@ the Web. By exposing a complex application such as a Webmail, you should be awar
the security implications caused by such an increase of attack surface.<p> the security implications caused by such an increase of attack surface.<p>
<div class="form-group"> <div class="form-group">
<label>Enable Web email client (and path to the Web email client)</label> <label>Enable Web email client (and path to the Web email client)</label>
<!-- <div class="radio"> -->
<!-- {{ macros.radio("webmail_type", "roundcube", "RoundCube", "popular Webmail running on top of PHP") }} -->
<!-- {{ macros.radio("webmail_type", "rainloop", "Rainloop", "lightweight Webmail based on PHP, no database") }} -->
<!-- </div> -->
<br/> <br/>
<select class="btn btn-primary dropdown-toggle" name="webmail_type" id="webmail"> <select class="btn btn-primary dropdown-toggle" name="webmail_type" id="webmail">
{% for webmailtype in ["none", "roundcube", "rainloop"] %} {% for webmailtype in ["none", "roundcube", "snappymail"] %}
<option value="{{ webmailtype }}" >{{ webmailtype }}</option> <option value="{{ webmailtype }}" >{{ webmailtype }}</option>
{% endfor %} {% endfor %}
</select> </select>

@ -12,7 +12,7 @@ the security implications caused by such an increase of attack surface.<p>
<label>Enable Web email client (and path to the Web email client)</label> <label>Enable Web email client (and path to the Web email client)</label>
<br/> <br/>
<select class="btn btn-primary dropdown-toggle" name="webmail_type" id="webmail"> <select class="btn btn-primary dropdown-toggle" name="webmail_type" id="webmail">
{% for webmailtype in ["none", "roundcube", "rainloop"] %} {% for webmailtype in ["none", "roundcube", "snappymail"] %}
<option value="{{ webmailtype }}" >{{ webmailtype }}</option> <option value="{{ webmailtype }}" >{{ webmailtype }}</option>
{% endfor %} {% endfor %}
</select> </select>

@ -72,10 +72,10 @@ services:
args: args:
VERSION: ${PINNED_MAILU_VERSION:-local} VERSION: ${PINNED_MAILU_VERSION:-local}
rainloop: snappymail:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}rainloop:${PINNED_MAILU_VERSION:-local} image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}snappymail:${PINNED_MAILU_VERSION:-local}
build: build:
context: ../webmails/rainloop context: ../webmails/snappymail
args: args:
VERSION: ${PINNED_MAILU_VERSION:-local} VERSION: ${PINNED_MAILU_VERSION:-local}

@ -53,7 +53,7 @@ DISABLE_STATISTICS=False
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN=true ADMIN=true
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL=none WEBMAIL=none
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)

@ -53,7 +53,7 @@ DISABLE_STATISTICS=False
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN=true ADMIN=true
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL=none WEBMAIL=none
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)

@ -53,7 +53,7 @@ DISABLE_STATISTICS=False
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN=true ADMIN=true
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL=none WEBMAIL=none
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)

@ -53,7 +53,7 @@ DISABLE_STATISTICS=False
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN=false ADMIN=false
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL=roundcube WEBMAIL=roundcube
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)

@ -88,7 +88,7 @@ services:
# Webmail # Webmail
webmail: webmail:
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}rainloop:${PINNED_MAILU_VERSION:-local} image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}snappymail:${PINNED_MAILU_VERSION:-local}
restart: always restart: always
env_file: mailu.env env_file: mailu.env
volumes: volumes:

@ -53,8 +53,8 @@ DISABLE_STATISTICS=False
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN=false ADMIN=false
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL=rainloop WEBMAIL=snappymail
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)
WEBDAV=none WEBDAV=none

@ -53,7 +53,7 @@ DISABLE_STATISTICS=False
# Expose the admin interface (value: true, false) # Expose the admin interface (value: true, false)
ADMIN=true ADMIN=true
# Choose which webmail to run if any (values: roundcube, rainloop, none) # Choose which webmail to run if any (values: roundcube, snappymail, none)
WEBMAIL=none WEBMAIL=none
# Dav server implementation (value: radicale, none) # Dav server implementation (value: radicale, none)

@ -0,0 +1 @@
Switch from RainLoop to SnappyMail. SnappyMail has better performance and is more secure.

@ -1,79 +0,0 @@
ARG ARCH=""
# 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 rainloop and roundloop
RUN apk add --no-cache \
python3 py3-pip tzdata \
&& pip3 install socrate==0.2.0
# https://www.rainloop.net/docs/system-requirements/
# Rainloop:
# cURL Builtin
# iconv php7-iconv
# json php7-json
# libxml php7-xml
# dom php7-dom
# openssl php7-openssl
# DateTime Builtin
# PCRE Builtin
# SPL Builtin
# Recommended:
# php7-fpm FastCGI Process Manager
# Optional PHP extension (for contacts):
# php7-pdo Accessing databases in PHP
# php7-pdo_sqlite Access to SQLite 3 databases
RUN apk add --no-cache \
nginx \
php7 php7-fpm php7-curl php7-iconv php7-json php7-xml php7-simplexml php7-dom php7-openssl php7-pdo php7-pdo_sqlite \
&& rm /etc/nginx/http.d/default.conf \
&& rm /etc/php7/php-fpm.d/www.conf \
&& mkdir -p /run/nginx \
&& mkdir -p /var/www/rainloop \
&& mkdir -p /config
# nginx / PHP config files
COPY config/nginx-rainloop.conf /config/nginx-rainloop.conf
COPY config/php-rainloop.conf /etc/php7/php-fpm.d/rainloop.conf
# Rainloop login
COPY login/include.php /var/www/rainloop/include.php
COPY login/sso.php /var/www/rainloop/sso.php
# Parsed en moved at startup
COPY defaults/php.ini /defaults/php.ini
COPY defaults/application.ini /defaults/application.ini
COPY defaults/default.ini /defaults/default.ini
# Install Rainloop from source
ENV RAINLOOP_URL https://github.com/RainLoop/rainloop-webmail/releases/download/v1.16.0/rainloop-community-1.16.0.zip
RUN apk add --no-cache \
curl unzip \
&& cd /var/www/rainloop \
&& curl -L -O ${RAINLOOP_URL} \
&& unzip -q *.zip \
&& rm -f *.zip \
&& rm -rf data/ \
&& find . -type d -exec chmod 755 {} \; \
&& find . -type f -exec chmod 644 {} \; \
&& chown -R nginx:nginx /var/www/rainloop \
&& apk del unzip
COPY start.py /start.py
COPY config.py /config.py
EXPOSE 80/tcp
VOLUME ["/data"]
CMD /start.py
HEALTHCHECK CMD curl -f -L http://localhost/ || exit 1
RUN echo $VERSION >> /version

@ -1,41 +0,0 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/rainloop;
# /dev/stdout (Default), <path>, off
access_log off;
# /dev/stderr (Default), <path>, debug, info, notice, warn, error, crit, alert, emerg
error_log /dev/stderr warn;
index index.php;
# set maximum body size to configured limit
client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
location / {
try_files $uri /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_keep_conn on;
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/php7-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
location ^~ /data {
deny all;
}
}

@ -1,31 +0,0 @@
<?php
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
if (!defined('APP_VERSION')) {
$version = file_get_contents('/data/VERSION');
if ($version) {
define('APP_VERSION', $version);
define('APP_INDEX_ROOT_FILE', __FILE__);
define('APP_INDEX_ROOT_PATH', str_replace('\\', '/', rtrim(dirname(__FILE__), '\\/').'/'));
}
}
if (file_exists(APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php')) {
include APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php';
} else {
echo '[105] Missing version directory';
exit(105);
}
// Retrieve email and password
if (isset($_SERVER['HTTP_X_REMOTE_USER']) && isset($_SERVER['HTTP_X_REMOTE_USER_TOKEN'])) {
$email = $_SERVER['HTTP_X_REMOTE_USER'];
$password = $_SERVER['HTTP_X_REMOTE_USER_TOKEN'];
$ssoHash = \RainLoop\Api::GetUserSsoHash($email, $password);
// redirect to webmail sso url
header('Location: index.php?sso&hash='.$ssoHash);
}
else {
header('HTTP/1.0 403 Forbidden');
}

@ -0,0 +1,86 @@
ARG ARCH=""
# 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
# libxml php7-xml
# dom php7-dom
# Optional extensions:
# cURL php7-curl
# exif php7-exif
# gd, gmagick or imagemagick gd and php7-gd
# gnupg gpgme and alpine has no php7-gnupg library :(
# iconv php7-iconv
# intl php7-intl
# ldap we don't use ldap
# openssl php7-openssl
# PDO (MySQL/PostgreSQL/SQLite) (for contacts) php7-pdo_sqlite and php7-pdo
# redis NOT USED
# Sodium php7-sodium and libsodium
# Tidy php7-tidy
# uuid (PECL) php7-pecl-uuid
# xxtea (PECL) not found on alpine repo
# zip php7-zip
#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 \
&& rm /etc/nginx/http.d/default.conf \
&& rm /etc/php7/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
# Parsed and moved at startup
COPY defaults/php.ini /defaults/php.ini
COPY defaults/application.ini /defaults/application.ini
COPY defaults/default.ini /defaults/default.ini
# Install Snappymail from source
ENV SNAPPYMAIL_URL https://github.com/the-djmaze/snappymail/releases/download/v2.13.4/snappymail-2.13.4.zip
RUN cd /var/www/webmail \
&& busybox wget ${SNAPPYMAIL_URL} -O - | busybox unzip - \
&& chmod -R u+w,a+rX /var/www/webmail \
&& chown -R nginx:nginx /var/www/webmail
# SnappyMail login
COPY login/include.php /var/www/webmail/include.php
COPY login/sso.php /var/www/webmail/sso.php
COPY start.py /start.py
COPY config.py /config.py
EXPOSE 80/tcp
VOLUME ["/data"]
CMD /start.py
HEALTHCHECK CMD curl -f -L http://localhost/ping || exit 1
RUN echo $VERSION >> /version

@ -10,6 +10,6 @@ args = os.environ.copy()
log.basicConfig(stream=sys.stderr, level=args.get("LOG_LEVEL", "WARNING")) log.basicConfig(stream=sys.stderr, level=args.get("LOG_LEVEL", "WARNING"))
# Build final configuration paths # Build final configuration paths
conf.jinja("/config/nginx-rainloop.conf", args, "/etc/nginx/http.d/rainloop.conf") conf.jinja("/config/nginx-snappymail.conf", args, "/etc/nginx/http.d/snappymail.conf")
if os.path.exists("/var/run/nginx.pid"): if os.path.exists("/var/run/nginx.pid"):
os.system("nginx -s reload") os.system("nginx -s reload")

@ -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/php7-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/php7-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}

@ -1,7 +1,7 @@
; Start a new pool named 'rainloop'. ; Start a new pool named 'snappymail'.
; the variable $pool can be used in any directive and will be replaced by the ; the variable $pool can be used in any directive and will be replaced by the
; pool name ('rainloop' here) ; pool name ('snappymail' here)
[rainloop] [snappymail]
; Redirect worker stdout and stderr into main error log. If not set, stdout and ; 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. ; stderr will be redirected to /dev/null according to FastCGI specs.
@ -99,3 +99,20 @@ pm.process_idle_timeout = 10s
; Equivalent to PHP_FCGI_MAX_REQUESTS. Default value: 0. ; Equivalent to PHP_FCGI_MAX_REQUESTS. Default value: 0.
; Noted: Used only when pm is set to 'ondemand' ; Noted: Used only when pm is set to 'ondemand'
pm.max_requests = 200 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

@ -1,4 +1,4 @@
; RainLoop Webmail configuration file ; Snappymail Webmail configuration file
[webmail] [webmail]
attachment_size_limit = {{ MAX_FILESIZE }} attachment_size_limit = {{ MAX_FILESIZE }}
@ -8,7 +8,11 @@ allow_admin_panel = Off
[labs] [labs]
allow_gravatar = Off allow_gravatar = Off
{% if WEB_WEBMAIL == '/' %}
custom_login_link='sso.php' custom_login_link='sso.php'
{% else %}
custom_login_link='{{ WEB_WEBMAIL }}/sso.php'
{% endif %}
custom_logout_link='/sso/logout' custom_logout_link='/sso/logout'
[contacts] [contacts]

@ -0,0 +1,17 @@
<?php
$_ENV['SNAPPYMAIL_INCLUDE_AS_API'] = true;
require 'index.php';
// Retrieve email and password
if (isset($_SERVER['HTTP_X_REMOTE_USER']) && isset($_SERVER['HTTP_X_REMOTE_USER_TOKEN'])) {
$email = $_SERVER['HTTP_X_REMOTE_USER'];
$password = $_SERVER['HTTP_X_REMOTE_USER_TOKEN'];
$ssoHash = \RainLoop\Api::CreateUserSsoHash($email, $password);
// redirect to webmail sso url
header('Location: index.php?sso&hash='.$ssoHash);
}
else {
header('HTTP/1.0 403 Forbidden');
}
?>

@ -27,7 +27,7 @@ conf.jinja("/defaults/php.ini", os.environ, "/etc/php7/php.ini")
os.system("php-fpm7") os.system("php-fpm7")
os.system("chown -R nginx:nginx /data") os.system("chown -R nginx:nginx /data")
os.system("chmod -R a+rX /var/www/rainloop/") os.system("chmod -R a+rX /var/www/webmail/")
subprocess.call(["/config.py"]) subprocess.call(["/config.py"])
os.execv("/usr/sbin/nginx", ["nginx", "-g", "daemon off;"]) os.execv("/usr/sbin/nginx", ["nginx", "-g", "daemon off;"])
Loading…
Cancel
Save