Mail server on QNAP with Mailu container based application

One time I wanted to run a mail server on my QNAP but couldn’t find software that would allow me to deploy my own mail server. I tried to look for other ways to run my server and decided to use Container Station and container based applications. After a short search, I found Mailu mail server, which fits my needs perfectly.

I will now give a brief description of how I planned to run this application. Firstly it was to launch Mailu application using generator from their documentation to create docker-compose.yml file. Then after starting the application the next step was to correctly configure the DNS records for mail service. The final stage would be to provide access to my QNAP, which is running on a LAN and is not exposed to the Internet (for security reasons and recently discovered vulnerabilities). This will be accomplished by setting up a proxy on my nginx web server and port forwarding on my router running on pfSense. In the following post I will describe how this was configured and welcome you to read on.

Installing Mailu on QNAP

The first step is to install the Container Station software on our QNAP. To do this, start AppCenter and enter “container station” in the search box and then click install. After successful installation, you need to create your own application in Container Station. To do this, click Create, then Create Application and enter a name for the application. To create your own application, delete everything and leave only the line: version ‘3’ (this will be changed), but for now you need to create a directory with the application and then click Create.

Now application directory in our case is /share/Container/container-station-data/application/mailutest. FileStation shows that docker-compose.yml file is stored on that location so next step is to create our docker-compose.yml and env files. To do that we may use generator on Mailu site. I share my file below:

# This file is auto-generated by the Mailu configuration wizard.
# Please read the documentation before attempting any change.
# Generated for compose flavor

version: '2.2'

services:

  # External dependencies
  redis:
    image: redis:alpine
    restart: always
    volumes:
      - "/share/Container/container-station-data/application/mailutest/redis:/data"
    dns:
      - 192.168.203.254

  # Core services
  front:
    image: mailu/nginx:1.9
    restart: always
    env_file: mailu.env
    logging:
      driver: json-file
    ports:
      - "0.0.0.0:81:80"
      - "0.0.0.0:444:443"
      - "0.0.0.0:25:25"
      - "0.0.0.0:465:465"
      - "0.0.0.0:587:587"
      - "0.0.0.0:110:110"
      - "0.0.0.0:995:995"
      - "0.0.0.0:143:143"
      - "0.0.0.0:993:993"
    volumes:
      - "/share/Container/container-station-data/application/mailutest/certs:/certs"
      - "/share/Container/container-station-data/application/mailutest/overrides/nginx:/overrides:ro"
    depends_on:
      - resolver
    dns:
      - 192.168.203.254

  resolver:
    image: mailu/unbound:1.9
    env_file: mailu.env
    restart: always
    networks:
      default:
        ipv4_address: 192.168.203.254

  admin:
    image: mailu/admin:1.9
    restart: always
    env_file: mailu.env
    volumes:
      - "/share/Container/container-station-data/application/mailutest/data:/data"
      - "/share/Container/container-station-data/application/mailutest/dkim:/dkim"
    depends_on:
      - redis
      - resolver
    dns:
      - 192.168.203.254

  imap:
    image: mailu/dovecot:1.9
    restart: always
    env_file: mailu.env
    volumes:
      - "/share/Container/container-station-data/application/mailutest/mail:/mail"
      - "/share/Container/container-station-data/application/mailutest/overrides/dovecot:/overrides:ro"
    depends_on:
      - front
      - resolver
    dns:
      - 192.168.203.254

  smtp:
    image: mailu/postfix:1.9
    restart: always
    env_file: mailu.env
    volumes:
      - "/share/Container/container-station-data/application/mailutest/mailqueue:/queue"
      - "/share/Container/container-station-data/application/mailutest/overrides/postfix:/overrides:ro"
    depends_on:
      - front
      - resolver
    dns:
      - 192.168.203.254

  antispam:
    image: mailu/rspamd:1.9
    hostname: antispam
    restart: always
    env_file: mailu.env
    volumes:
      - "/share/Container/container-station-data/application/mailutest/filter:/var/lib/rspamd"
      - "/share/Container/container-station-data/application/mailutest/overrides/rspamd:/etc/rspamd/override.d:ro"
    depends_on:
      - front
      - resolver
    dns:
      - 192.168.203.254

  # Optional services



  # Webmail
  webmail:
    image: mailu/roundcube:1.9
    restart: always
    env_file: mailu.env
    volumes:
      - "/share/Container/container-station-data/application/mailutest/webmail:/data"
      - "/share/Container/container-station-data/application/mailutest/overrides/roundcube:/overrides:ro"
    depends_on:
      - imap
      - resolver
    dns:
      - 192.168.203.254


networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 192.168.203.0/24

As you can see my file was modified with directories which is the same as on my QNAP.

# Mailu main configuration file
#
# This file is autogenerated by the configuration management wizard for compose flavor.
# For a detailed list of configuration variables, see the documentation at
# https://mailu.io

###################################
# Common configuration variables
###################################

# Set to a randomly generated 16 bytes string
SECRET_KEY=xxxxxxxxxxxxxxxxx

# Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)
SUBNET=192.168.203.0/24

# Main mail domain
DOMAIN=bnrs.pl

# Hostnames for this server, separated with comas
HOSTNAMES=mailutest.bnrs.pl

# Postmaster local part (will append the main mail domain)
POSTMASTER=admin

# Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt)
TLS_FLAVOR=mail-letsencrypt

# Authentication rate limit per IP (per /24 on ipv4 and /56 on ipv6)
AUTH_RATELIMIT_IP=60/hour

# Authentication rate limit per user (regardless of the source-IP)
AUTH_RATELIMIT_USER=100/day

# Opt-out of statistics, replace with "True" to opt out
DISABLE_STATISTICS=False

###################################
# Optional features
###################################

# Expose the admin interface (value: true, false)
ADMIN=true

# Choose which webmail to run if any (values: roundcube, rainloop, none)
WEBMAIL=roundcube

# Dav server implementation (value: radicale, none)
WEBDAV=none

# Antivirus solution (value: clamav, none)
ANTIVIRUS=none

###################################
# Mail settings
###################################

# Message size limit in bytes
# Default: accept messages up to 50MB
# Max attachment size will be 33% smaller
MESSAGE_SIZE_LIMIT=50000000

# Message rate limit (per user)
MESSAGE_RATELIMIT=200/day

# Networks granted relay permissions
# Use this with care, all hosts in this networks will be able to send mail without authentication!
RELAYNETS=

# Will relay all outgoing mails if configured
RELAYHOST=

# Fetchmail delay
FETCHMAIL_DELAY=600

# Recipient delimiter, character used to delimiter localpart from custom address part
RECIPIENT_DELIMITER=+

# DMARC rua and ruf email
DMARC_RUA=admin
DMARC_RUF=admin

# Welcome email, enable and set a topic and body if you wish to send welcome
# emails to all users.
WELCOME=false
WELCOME_SUBJECT=Welcome to your new email account
WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!

# Maildir Compression
# choose compression-method, default: none (value: gz, bz2, lz4, zstd)
COMPRESSION=
# change compression-level, default: 6 (value: 1-9)
COMPRESSION_LEVEL=

# IMAP full-text search is enabled by default. Set the following variable to off in order to disable the feature.
# FULL_TEXT_SEARCH=off

###################################
# Web settings
###################################

# Path to redirect / to
WEBROOT_REDIRECT=/webmail

# Path to the admin interface if enabled
WEB_ADMIN=/admin

# Path to the webmail if enabled
WEB_WEBMAIL=/webmail

# Website name
SITENAME=Mailu bnrs.pl

# Linked Website URL
WEBSITE=https://mailutest.bnrs.pl



###################################
# Advanced settings
###################################

# Log driver for front service. Possible values:
# json-file (default)
# journald (On systemd platforms, useful for Fail2Ban integration)
# syslog (Non systemd platforms, Fail2Ban integration. Disables `docker-compose log` for front!)
# LOG_DRIVER=json-file

# Docker-compose project name, this will prepended to containers names.
COMPOSE_PROJECT_NAME=mailu

# Number of rounds used by the password hashing scheme
CREDENTIAL_ROUNDS=12

# Header to take the real ip from
REAL_IP_HEADER=

# IPs for nginx set_real_ip_from (CIDR list separated by commas)
REAL_IP_FROM=

# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
REJECT_UNLISTED_RECIPIENT=

# Log level threshold in start.py (value: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET)
LOG_LEVEL=WARNING

# Timezone for the Mailu containers. See this link for all possible values https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
TZ=Etc/UTC

###################################
# Database settings
###################################
DB_FLAVOR=sqlite

##################################
# ADMIN # After creating user please remove below lines !!!
##################################
INITIAL_ADMIN_ACCOUNT = admin 
INITIAL_ADMIN_DOMAIN = bnrs.pl 
INITIAL_ADMIN_PW = xxxxxx
INITIAL_ADMIN_MODE = update

If we have generated files env file must be uploaded to directory on QNAP. To do that you need to upload file or log via ssh and create it. Then edit application and paste content of docker-compose.yml. After that start application.

Let’s check that the application is running in Container Station. I checked this using the docker command and the application is running and the web panel is accessible.

docker ps command running on qnap console
Mailu web panel running on QNAP IP address

Expose Mailu server to the Internet

The first thing will be to add an MX record in DNS (I won’t write how to do this, as there are many tutorials on the internet about this). The next step is to create port forwarding on the router. In my case, the router is running pfSense, on which I created the port forwarding rules needed to serve mail to my QNAP. Once the forwarding rules are created, the WAN rules are created automatically and can be turned off when needed. I will not describe how to create these rules and feel free to use the documentation as I did 🙂

The next step is to create a proxy rule on the web server, as I only have one in my infrastructure, so the domain I want to use as my mail server (mailutest.bnrs.pl) needs to be redirected to the correct server – in my case it’s the QNAP IP address. I pasted the code below into my nginx configuration and reloaded the server.

server  {
        listen  80;
        listen 443 ssl;
        server_name mailutest.bnrs.pl;

        access_log  /var/log/nginx/bnrs.pl.access.log;
        error_log  /var/log/nginx/bnrs.pl.error_log;

        ssl_certificate /etc/letsencrypt/live/bnrs.pl/cert.pem;
        ssl_certificate_key /etc/letsencrypt/live/bnrs.pl/privkey.pem;

        location  / {
                proxy_pass  http://192.168.xxx.xxx:81/;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }
}

After this configuration, we now have everything we need to run the mail server. Let’s test it in a basic test – sending and receiving emails. As you can see below the mail server is running on my domain.

Short test in mail sending and receiving from newly created Mailu server on QNAP

As you can see from the example above, it is possible to run an email server on a QNAP device. With Container Station, we can take advantage of docker technology and deploy container-based applications. This gives us a lot of possibilities and makes QNAP more useful than just a file storage device. Today, many applications can be run in containers and their popularity continues to grow. I hope you will find the above tutorial useful and it will save you some searching if like me you would like to have a mail server on your QNAP.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 comments
Inline Feedbacks
View all comments