0

First, my structure. Running Ubuntu 16.04.3 with Apache 2.4, I have a site at /mnt/WWW but never serves pages from there except for a login form. Everything is redirected to www. if not another subdomain and then redirected from http to https. I also have an authentication form running from the /mnt/WWW directory. This allows me to have a single php form that serves the mod_auth_form authentication for any url, path or reverse proxy.

I have spent over 12 hours getting this all working to this point, and have learnt a great deal about all of this, but am stuck on one last thing. But before that here some info regarding my existing (and working) setup.

Server directory structure.

  • /mnt/WWW - Root Apache Directory
  • /mnt/WWW/www.example.com - Root Directory of Site
  • /mnt/WWW/dev.example.com - Root of Development Site

My current Virtual Hosts file:

# Default
ServerName example.com
DocumentRoot /mnt/WWW
ServerAdmin support@example.com
RemoteIPHeader X-Forwarded-For

Alias "/login.php" "/mnt/WWW/login.php"
Alias "/logo.png" "/mnt/WWW/logo.png"

<Directory />
    # Allow access to excluded directories
    SetEnvIf Request_URI "login.php" allow
    SetEnvIf Request_URI "logo.png"  allow
    Order allow,deny
    Allow from env=allow
    Satisfy any
    Require valid-user
</Directory>

<Location />
    AuthFormProvider file
    AuthType form
    AuthName "Reserved Area"
    Session On
    SessionCookieName session path=/
    SessionCryptoPassphrase secret
    SessionMaxAge 300
    require valid-user

    # This is the login page
    ErrorDocument 401 /login.php

    # This is the file containing users login data
    AuthUserFile /mnt/WWW/.htpasswd
</Location>

# Default HTTP
<VirtualHost *:80>
    DocumentRoot "/mnt/WWW"
    ServerName example.com

    <Directory />
        Require valid-user
    </Directory>

    # Force SSL
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}:443$1 [R,L]

    # Force WWW Subdomain
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^[0-9a-zA-Z-]+\.[a-zA-Z]{2,}$
    RewriteRule ^(.*)$ https://www.%{HTTP_HOST}:443$1 [R=301,L]
</VirtualHost>

# Default HTTPS
<VirtualHost *:443>
    DocumentRoot "/mnt/WWW"
    ServerName example.com

    <Directory />
        Require valid-user
    </Directory>

    # Force WWW Subdomain
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^[0-9a-zA-Z-]+\.[a-zA-Z]{2,}$
    RewriteRule ^(.*)$ https://www.%{HTTP_HOST}:443$1 [R=301,L]

    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt
</VirtualHost>

# Default WWW
<VirtualHost *:443>
    DocumentRoot "/mnt/WWW/www.example.com"
    ServerName www.example.com

    <Directory />
        Require valid-user
    </Directory>

    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt
</VirtualHost>

#Reverse Proxies
<VirtualHost *:443>
    # NAS
    DocumentRoot /mnt/WWW

    ServerName nas.example.com
    ServerAlias nas.example.com

    <Directory /mnt/WWW/>
        Require valid-user
    </Directory>

    ProxyPass /logo.png !
    ProxyPass /login.php !
    ProxyPass / http://10.0.28.1:5000/
    ProxyPassReverse / http://10.0.28.1:5000/

    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt
</VirtualHost>

Now, as you can see I have a login.php and logo.png file for the form. I plan on changing this to a form for LDAP and have no issues with that, and I am planning on styling it further as well. This means I will end up with more files to include in the configuration for the login.

In saying that, I want to move the login files to /mnt/WWW/authentication folder. I was hoping that I could then instead of making rules etc for 2+ individual files, I could simply set those to the directory itself. All the things like the Alias, noauth setting etc.

But I cannot seem to get it all to work. Any help will be appreciated.

PS: I am a beginner with all of this, and if someone see's any potential security issues please advise.

UPDATE: I reworked the config working thru each step and making sure I used full paths etc. I have everything so far working, that is:

  • All Port 80 is redirect to 443
  • All requests redirect to www.example.com unless its a subdomain
  • Redirect some subfolders to a folder outside for services such as phpmyadmin.
  • Reverse Proxy subdomains to relevant server, and access different services on said server using subfolder eg. nas.examle.com is NAS GUI while nas.example.com/webmin is NAS Webmin UI.

Here is an update of my config so far.

<VirtualHost *:80>
    # Redirect anything on port 80 to port 443
    #ServerName example.com
    ServerAdmin support@example.com
    DocumentRoot /mnt/WWW

    # Force SSL
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}:443$1 [R,L]

    # Error Logs
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAdmin support@example.com
    DocumentRoot /mnt/WWW

    # Force WWW Subdomain
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^[0-9a-zA-Z-]+\.[a-zA-Z]{2,}$
    RewriteRule ^(.*)$ https://www.%{HTTP_HOST}:443$1 [R=301,L]

    # SSL Certificates
    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt

    # Error Logs
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:443>
    ServerName www.example.com
    ServerAdmin support@example.com
    DocumentRoot /mnt/WWW/www.example.com

    <Directory /mnt/WWW/www.example.com>
        Options Indexes FollowSymLinks
        AllowOverride all
        Require all granted
    </Directory>

    <Directory /mnt/WWW/phpmyadmin>
        Options Indexes FollowSymLinks
        AllowOverride all
        Require all granted
    </Directory>

    # Map PHPMyAdmin to another folder
    Alias "/phpmyadmin" "/mnt/WWW/phpmyadmin"

    # WEBMIN
    ProxyPass "/webmin" "http://localhost:10000/"
    ProxyPassReverse "/webmin" "http://localhost:10000/"

    # SSL Certificates
    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt

    # Error Logs
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

# Reverse Proxies

<VirtualHost *:443>
    # NAS
    ServerName nas.example.com
    ServerAdmin support@example.com
    DocumentRoot /mnt/WWW

    # NAS 2
    ProxyPass "/nas2" "http://10.0.28.3:5000/"
    ProxyPassReverse "/nas2" "http://10.0.28.3:5000/"

    # NAS 1
    ProxyPass "/nas1" "http://10.0.28.2:5000/"
    ProxyPassReverse "/nas1" "http://10.0.28.2:5000/"

    # NAS CLUSTER
    ProxyPass / http://10.0.28.1:5000/
    ProxyPassReverse / http://10.0.28.1:5000/

    # SSL Certificates
    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt

    # Error Logs
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Now what I am trying to do is use a subfolder from the document root, to hold all files relevant for authentication. At this stage is simply a form, an image, css file and the .htaccess with credentials. This will change a little later to a form that will validate against an LDAP server instead of the .htaccess.

My goal is to lock down ALL access to the server, weather the local site, phpmyadmin or a reverseproxy, so I get the authform (in /mnt/WWW/example.login/) before given access to what was requested.

Now I have had this working before, so I believe my problem has something to do with the order or structure of the code, but so far no matter what I try I am getting a Internal Server Error.

I changed the final www.example.com virtualhost to the following:

<VirtualHost *:443>
    ServerName www.example.com
    ServerAdmin support@example.com
    DocumentRoot /mnt/WWW/www.example.com

    <Directory /mnt/WWW/www.example.com>
        Options Indexes FollowSymLinks
        AllowOverride all
        Require valid-user
    </Directory>

    <Location /mnt/WWW>
        AuthFormProvider file
        AuthType form
        AuthName "Reserved Area"

        Session On
        SessionCookieName session path=/;domain=.example.com;httponly;secure
        SessionCryptoPassphrase secret
        SessionMaxAge 300
        require valid-user

        ErrorDocument 401 /example.login/index.php
        AuthUserFile /mnt/WWW/example.login/.htpasswd
    </Location>

    <Directory /mnt/WWW/phpmyadmin>
        Options Indexes FollowSymLinks
        AllowOverride all
        Require all granted
    </Directory>

    # Map PHPMyAdmin to another folder
    Alias "/phpmyadmin" "/mnt/WWW/phpmyadmin"

    # WEBMIN
    ProxyPass "/webmin" "http://localhost:10000/"
    ProxyPassReverse "/webmin" "http://localhost:10000/"

    # SSL Certificates
    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt

    # Error Logs
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

What is it I am doing wrong. Is it ordering, or have I overlooked something? Been on this for hours and is driving me nuts. I just need some fresh (and experienced) eys on this. Thanks.

BTW, just for clarity, all paths and domains are correct as I have them IRL. I only changed the real domain name used, to example.com etc to hide the real one.

Another Update:

I read somewhere (can't find again) that I can use the Auth stuff on the directory tag instead of the location. I read it was more secure. Not sure if its true or not, but I did get a config that sorta works:

<VirtualHost *:443>
    ServerName www.example.com
    ServerAdmin support@example.com
    DocumentRoot /mnt/WWW/www.example.com

    # Map PHPMyAdmin to another folder
    Alias "/example.login" "/mnt/WWW/example.login"

    <Directory "/mnt/WWW/example.login">
        Order allow,deny
        Allow from all
        Satisfy any
    </Directory>

    # Map PHPMyAdmin to another folder
    Alias "/phpmyadmin" "/mnt/WWW/phpmyadmin"

    <Directory /mnt/WWW/phpmyadmin>
        Order allow,deny
        Allow from all
        Satisfy any
    </Directory>

    <Directory /mnt/WWW/www.example.com>
        Options Indexes FollowSymLinks
        AllowOverride all
        Require valid-user

        AuthFormProvider file
        AuthType form
        AuthName "Reserved Area"

        Session On
        SessionCookieName session path=/;domain=.example.com;httponly;secure
        SessionCryptoPassphrase secret
        SessionMaxAge 300
        Require valid-user

        ErrorDocument 401 /example.login/index.php
        AuthUserFile /mnt/WWW/example.login/.htpasswd
    </Directory>

    # WEBMIN
    ProxyPass "/webmin" "http://localhost:10000/"
    ProxyPassReverse "/webmin" "http://localhost:10000/"

    # SSL Certificates
    SSLEngine on
    SSLCertificateFile /root/ssl/example.com.crt
    SSLCertificateKeyFile /root/ssl/private.key
    SSLCACertificateFile /root/ssl/intermediateCA.crt

    # Error Logs
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Now, this config, gives me a partial form, and I am able to login and get the main root www.example.com site. phpmyadmin is not secured, and example.login is also not secured. I plan on securing phpmyadmin and others later, just doing 1 step at a time.

When I say partial, I mean the form shows, but there is an image in the page that is not showing. I think it is a security issue, as the page shows normally when no auth is in the config.

So My issue right now is the following, how can I have the example.login folder and ALL files in it bypass auth, and is there not a better way to put in the auth code so to apply to everything and controll what is locked with the Require valid-user?

  • you should start by defining directories correctly and define actual functionality in the intended virtualhost in the correct directory. You are defining "Directory /" when that is pointing to the / of your filesystem (not the documentroot), you also define a Location / which is overriding all / in all virtualhosts because you don't re-define it in any virtualhost. Consider using Location only to override behaviour of virtual uri-path and use Directory when you are applying configurations to real directories in the filesystem. – Daniel Ferradal Dec 21 '17 at 10:32
  • I font understand what you mean by the directory / behind filesystem root? All paths are defined on the basis that mnt/WWW/ is the document root and all seems to work fine as on everything seems to use the correct paths. Also location is only defined once outside virtual hosts and the current behaviour shows its being applied to all virtual hosts. Not saying your wrong, just need to understand the logic so I can learn and do this better. – Shaun Williams Dec 21 '17 at 13:28
  • PS: Reason that the document root is /mnt/WWW and seems to be a root filesystem is because it is actually a mounted nfs share to a NAS where we keep all the website files together. – Shaun Williams Dec 21 '17 at 13:31
  • I am working thru a clean file right now, working on each step one by one. I still don't understand the above but am still trying to rectify. Will post back if and when I have more information or I still have the same problem. – Shaun Williams Dec 22 '17 at 04:12
  • Updated the question. – Shaun Williams Dec 23 '17 at 04:13
  • "Location /mnt/www" makes no sense. As I mentioned Location is for virtual uri, that is, uri that are constructed from documentroot, they do not need to exist in your filesystem. For real directories always use Directory. – Daniel Ferradal Dec 23 '17 at 20:45
  • I have learnt that thankyou. I now have it as / but plan on not using location in final code as I read somewhere it's more secure to have the Auth stuff in the directory tag. Still doesn't help too much thou as I still seem unable to get away from a 500 error. – Shaun Williams Dec 24 '17 at 01:04
  • It will probably help if you set AllowOverride to none and also if you read the error log. – Daniel Ferradal Dec 26 '17 at 15:45

0 Answers0