Home > Software design >  Running Apache (with .htaccess) App Behind Nginx Rerverse Proxy
Running Apache (with .htaccess) App Behind Nginx Rerverse Proxy

Time:02-10

I've recently begun trying to Dockerize my services and I'm to the point of Dockerizing everything that already has an image built. Now I'm trying to build an image for facileManager (FM) which doesn't yet have one. I've got it mostly working but I'm having an issue when running it behind Nginx. FM is normally an apache-php app and doesn't include install instructions for Nginx. What I've noticed with my container/image is that it works ok when I connect directly to it through a published port but if I try to connect to it through Nginx it errors out complaining about the .htaccess file not working. I'm not an expert in either Apache or Nginx so I did my Googleing but didn't come up with much beyond Wordpress having a similar issue with it's "pretty urls" so I'm hoping someone here can give a hand.

First here is the Github repo for the app: https://github.com/WillyXJ/facileManager/tree/ea159f5f6112727de8422c552aa05b6682aa4d79/server

The .htaccess file specifically is:

<IfModule mod_headers.c>
    <FilesMatch "\.(js|css|txt)$">
        Header set Cache-Control "max-age=7200"
    </FilesMatch>
    <FilesMatch "\.(jpe?g|png|gif|ico)$">
        Header set Cache-Control "max-age=2592000"
    </FilesMatch>
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
</IfModule>

The exact error I'm getting is from here: https://github.com/WillyXJ/facileManager/blob/ea159f5f6112727de8422c552aa05b6682aa4d79/server/fm-includes/init.php#L153

if (!defined('INSTALL')) {
        if (@dns_get_record($_SERVER['SERVER_NAME'], DNS_A   DNS_AAAA)) {
            $test_output = getPostData($GLOBALS['FM_URL'] . 'admin-accounts.php?verify', array('module_type' => 'CLIENT'));
            $test_output = isSerialized($test_output) ? unserialize($test_output) : $test_output;
            if (strpos($test_output, 'Account is not found.') === false) {
                $message = sprintf(_('The required .htaccess file appears to not work with your Apache configuration which is required by %1s. '
                        . 'AllowOverride None in your configuration may be blocking the use of .htaccess or %s is not resolvable.'),
                        $fm_name, $_SERVER['SERVER_NAME']);
                if ($single_check) {
                    bailOut($message);
                } else {
                    $requirement_check .= displayProgress(_('Test Rewrites'), false, 'display', $message);
                    $error = true;
                }
            } else {
                if (!$single_check) $requirement_check .= displayProgress(_('Test Rewrites'), true, 'display');
            }
        }
    }

Nginx config:

server {
        listen 80;

        server_tokens off;

        location /.well-known/acme-challenge/ {
                root /var/www/certbot;
        }

        location / {
                return 301 https://$host$request_uri;
        }
}

server {
        listen 443 ssl;

        server_name bound.example.com;

        ssl_certificate /etc/nginx/ssl/live/bound.example.com/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/live/bound.example.com/privkey.pem;
        include /etc/nginx/ssl/options-ssl-nginx.conf;
        ssl_dhparam /etc/nginx/ssl/ssl-dhparams.pem;

        location / {
                proxy_pass http://FM.;     <<< Docker service name
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        }
}

My Dockerfile/commands run: https://github.com/MeCJay12/facileManager-docker

FROM php:7.4-apache

ENV TZ=UTC
ENV Version=4.2.0
ARG DEBIAN_FRONTEND=noninteractive
WORKDIR /src

RUN apt-get update \
    && apt-get -qqy install wget libldb-dev libldap2-dev tzdata \
    && wget http://www.facilemanager.com/download/facilemanager-complete-$Version.tar.gz \
    && tar -xvf facilemanager-complete-$Version.tar.gz \
    && mv facileManager/server/* /var/www/html/

RUN ln -s /usr/lib/x86_64-linux-gnu/libldap.so /usr/lib/libldap.so \
    && docker-php-ext-install mysqli ldap \
    && a2enmod rewrite dump_io

COPY php.ini /usr/local/etc/php/php.ini
RUN rm -r /src

Bonus question: When accessing this container/image directly through a published port, the images are all broken. I assume it's related since the .htaccess file includes references to images files.

Thanks in advance for the help!

CodePudding user response:

Found solution in https://github.com/WillyXJ/facileManager/issues/491. Needed to remove a check in the webapp that wasn't working quite right.

CodePudding user response:

Dot Points:

  • include $request_uri in your proxy pass
  • provide a resolver in your proxy location block
  • declare an entry for your container in Docker's network stack
  • use all lower case in your service name

Below is the configuration file I use to reverse proxy through to a Ubiquiti Unifi container. All my certbot is handled off site so I need not consider that here. If you compare our location blocks, the issue will likely become immediately apparent, but I'll explain for clarity's sake.

What you need to look at is your Proxy Pass directive. This is of course where the magic proxying happens. I notice that you have not been including the $request_uri, so any request nginx receives for bound.example.com/testpage1, it will send a request to the upstream apache server for bound.example.com. Of course if you need to include a port, as I have done here 8443, this is the place to do it also.

If you include this variable, it should resolve your problem.

The following does not answer your question, but I thought I would include it also just as some helpful information.

Also, I just want to note that I have included a resolver. The IP address 127.0.0.11 points to Docker's internal DNS resolver. Chances are you won't need to include this, however I did so myself to ensure I didn't get odd problems. Lastly, I'd just like to recommend that you look into upgrading your SSL settings, to ensure that you are safe from attacks from weaker SSL / TLS versions.

I expect that adding the variable $request_uri to your proxy pass directive is all that is required to get your site working.

server {
    listen       80;
    server_name  unifi.localdomain;

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen                     443 ssl;
    server_name                unifi.localdomain;

    add_header                 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;";

    ssl_protocols              TLSv1.3 TLSv1.2;
    ssl_session_cache          builtin:1000  shared:SSL:10m;
    ssl_session_timeout        1d;
    ssl_ciphers                ALL:!RSA:!CAMELLIA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SHA1:!SHA256:!SHA384;
    ssl_prefer_server_ciphers  on;
    ssl_stapling               on;
    ssl_stapling_verify        on;
    resolver                   8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout           5s;
    ssl_certificate            /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key        /etc/nginx/certs/privkey.pem;
    ssl_dhparam                /etc/nginx/certs/dhparam.pem;

    location / {
        resolver          127.0.0.11;
        proxy_pass        https://unifi:8443$request_uri;
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_set_header  X-Forwarded-For $remote_addr;
        proxy_set_header  Host $host;
        proxy_set_header  Upgrade $http_upgrade;
        proxy_set_header  Connection "Upgrade";
    }
}

ADDITIONALLY

Further to the above, I have had a chance to test this out in my own environment and was able to get it working, seemingly (although I did not go through the install procedure). I found that there would be no DNS entry in the docker resolver if I did not declare a network address on the docker network stack for this container. I used the following docker configuration;

version: "3.4"

services:
  fm:
    build: ./boundexample
    container_name: "fm"
    networks:
      primary:
        ipv4_address: "172.19.0.11"
  nginx:
    image: "nginx:stable"
    container_name: "nginx"
    restart: "unless-stopped"
    environment:
      TZ: "Australia/Perth"
    networks:
      primary:
        ipv4_address: "172.19.0.2"
    ports:
      - "10.0.0.4:80:80/tcp"
      - "10.0.0.4:443:443/tcp"
networks:
  primary:
    driver: bridge
    driver_opts:
      parent: enp3s0.2
    ipam:
      config:
        - subnet: "172.19.0.0/24"

where the directory boundexample pointed to a local copy of your github repository. My nginx configuration was the same as you provided, only I modified for my own SSL and used the following in my location block;

resolver          127.0.0.11;
proxy_pass http://fm$request_uri;

It is also possible that using FM in upper case within your docker configuration may cause you problems, I was unable to use upper case myself as docker-compose would not permit it.

  • Related