Mail-in-a-Box behind reverse proxy – limit admin web interface access

Did you install the Mailinabox (Mail-in-a-Box) solution and discover that your admin interface is publicly accessible? Me too, and there are no settings to limit this via GUI. My goal was to access admin interface only via my local network IP.

The Mail-in-a-Box web server runs on Nginx, and limiting IP access in Nginx is pretty simple. First, you need to find the config file. The default location in Mail-in-a-Box is /etc/nginx/conf.d/local.conf. But this file is overwritten if any changes are detected. So you actually need to modify two files, /etc/nginx/conf.d/local.conf and the template config file /root/mailinabox/conf/nginx-primaryonly.conf which Mail-in-a-Box uses to populate local.conf file. Open both files and modify the following section:

location /admin/assets {
                alias /usr/local/lib/mailinabox/vendor/assets;
        }
        rewrite ^/admin$ /admin/;
        rewrite ^/admin/munin$ /admin/munin/ redirect;
        location /admin/ {
                proxy_pass http://127.0.0.1:10222/;
                proxy_set_header X-Forwarded-For $remote_addr;
                add_header X-Frame-Options "DENY";
                add_header X-Content-Type-Options nosniff;
                add_header Content-Security-Policy "frame-ancestors 'none';";
        }

Change it to:

location /admin/assets {
                alias /usr/local/lib/mailinabox/vendor/assets;
        }
        rewrite ^/admin$ /admin/;
        rewrite ^/admin/munin$ /admin/munin/ redirect;
        location /admin/ {
                proxy_pass http://127.0.0.1:10222/;
                proxy_set_header X-Forwarded-For $remote_addr;
                add_header X-Frame-Options "DENY";
                add_header X-Content-Type-Options nosniff;
                add_header Content-Security-Policy "frame-ancestors 'none';";
                allow 192.168.60.2;
                deny all;
        }

We added the line “allow 192.168.60.2;” to grant admin access to the IP 192.168.60.2 and the line “deny all;” to deny access to everyone else. If you’re not running a reverse proxy in front of Mail-in-a-Box, you’re done. Be sure to change 192.168.60.2 to your local IP.

Save the changes and reload Nginx with the following command:

sudo service nginx reload

If you’re running a reverse proxy in front of Mail-in-a-Box, such as nginx proxy manager, you need to add some more settings to the Mail-in-a-Box nginx.conf file. When the reverse proxy passes requests to Mail-in-a-Box, it uses its own IP (the IP of the reverse proxy), so each request appears to come from the reverse proxy IP instead of the client’s IP. This would result in blocking all clients.

To circumvent this and obtain the correct client’s IP, you need to enable the Real IP Header module in the Mail-in-a-Box nginx.conf file. First open another template file /root/mailinabox/conf/nginx.conf, find this section and modify it:

# The secure HTTPS server.
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name $HOSTNAME;
...

Change it to:

# The secure HTTPS server.
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        set_real_ip_from 0.0.0.0/0;

        server_name $HOSTNAME;
...

Now open /etc/nginx/conf.d/local.conf and find this section:

# The secure HTTPS server.
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name yourdomain.com;
...

Change it to:

# The secure HTTPS server.
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        set_real_ip_from 0.0.0.0/0;

        server_name yourdomain.com;
...

Be sure to change yourdomain.com to your own domain.

Save the changes and reload Nginx with the following command:

sudo service nginx reload

Try accessing the admin interface from your local IP and then from another IP. Your local IP should have access, but other IPs should receive a forbidden error.

Here’s an example of the access log:

tail -f /var/log/nginx/access.log
192.168.60.2 - - [16/Jun/2023:17:59:15 +0200] "GET /admin HTTP/1.1" 200 39073
188.196.15.222 - - [16/Jun/2023:17:59:18 +0200] "GET /admin HTTP/1.1" 403 180

We can see that my local IP received a response code of 200, indicating a successful request, while the second IP received a response code of 403, meaning the server understood the request but refused to authorize it.

We modified the following files:

Running config files:
/etc/nginx/conf.d/local.conf

Template files:
/root/mailinabox/conf/nginx-primaryonly.conf
/root/mailinabox/conf/nginx.conf

Leave a Reply

Your email address will not be published. Required fields are marked *