Ssl – multiple vhosts on amazon ec2 instance: cannot access any other vhost than default

amazon ec2apache-2.4sslvirtualhost

I have an Amazon EC2 instance running Ubuntu 14.04 with Apache 2.4.
I have configured Apache with 3 virtual hosts, all for HTTPS only.

The problem is, when I try access the web server from the internet, the host name somehow gets lost and apache tries to serve the page from the default host, no matter by which hostname I accessed it.

/etc/apache2/sites-enabled/default-ssl.conf:

<VirtualHost *:80>
    ServerName monitor.mydomain.net
    Redirect / https://monitor.mydomain.net
</VirtualHost>

<VirtualHost *:443>
    ServerAdmin webmaster@localhost
    ServerName monitor.mydomain.net
    DocumentRoot /usr/share/nagios3/htdocs
    <Directory />
            Options FollowSymLinks
            AllowOverride None
            allow from all
    </Directory>
    <Directory /usr/share/nagios3/htdocs>
            Options Indexes FollowSymLinks MultiViews
            Options +ExecCGI
            AllowOverride None
            Order allow,deny
            allow from all
    </Directory>
    ScriptAlias /cgi-bin/nagios3 /usr/lib/cgi-bin/nagios3
    ScriptAlias /nagios3/cgi-bin /usr/lib/cgi-bin/nagios3
    Alias /stylesheets /etc/nagios3/stylesheets
    <DirectoryMatch (/usr/share/nagios3/htdocs|/usr/lib/cgi-bin/nagios3|/etc/nagios3/stylesheets)>
            Options FollowSymLinks
            DirectoryIndex index.php index.html
            AllowOverride AuthConfig
                <IfVersion < 2.3>
                    Order Allow,Deny
                    Allow From All
                </IfVersion>
                <IfVersion >= 2.3>
                    Require all denied
                </IfVersion>
                AuthName "Nagios Access"
            AuthType Basic
            AuthUserFile /etc/nagios3/htpasswd.users
            <RequireAny>
                    Require valid-user
            </RequireAny>
    </DirectoryMatch>
    ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
    <Directory "/usr/lib/cgi-bin">
            AllowOverride None
            Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
            Order allow,deny
            Allow from all
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/nagios_error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/nagios_access.log combined
    SSLEngine on

    SSLCertificateKeyFile /etc/ssl/private/a-wildcard.key
    SSLCertificateFile /etc/ssl/certs/a-wildcard+dhparam.pem
    SSLCertificateChainFile /etc/ssl/certs/gd_bundle-g2-g1.crt

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
            SSLOptions +StdEnvVars
    </FilesMatch>
    <Directory /usr/lib/cgi-bin>
            SSLOptions +StdEnvVars
    </Directory>
    BrowserMatch "MSIE [2-6]" \
            nokeepalive ssl-unclean-shutdown \
            downgrade-1.0 force-response-1.0
    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</VirtualHost>

/etc/apache2/sites-enabled/timetracker.conf:

<VirtualHost timetracker.mydomain.net:80>
    ServerName timetracker.mydomain.net
    Redirect / https://timetracker.mydomain.net
</VirtualHost>
<VirtualHost timetracker.mydomain.net:443>

    ServerAdmin webmaster@mydomain.net
    ServerName timetracker.mydomain.net

    DocumentRoot /var/www/kimai
    <Directory />
            Options FollowSymLinks
            AllowOverride None
    </Directory>
    <Directory /var/www/kimai>
            Options Indexes FollowSymLinks MultiViews
            AllowOverride None
            Order allow,deny
            allow from all
    </Directory>

    ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
    <Directory "/usr/lib/cgi-bin">
            AllowOverride None
            Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
            Order allow,deny
            Allow from all
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/timetracker_error.log

    LogLevel warn

    CustomLog ${APACHE_LOG_DIR}/timetracker_access.log combined

    SSLEngine on

    SSLCertificateKeyFile /etc/ssl/private/a-wildcard.key
    SSLCertificateFile /etc/ssl/certs/a-wildcard+dhparam.pem
    SSLCertificateChainFile /etc/ssl/certs/gd_bundle-g2-g1.crt

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
            SSLOptions +StdEnvVars
    </FilesMatch>
    <Directory /usr/lib/cgi-bin>
            SSLOptions +StdEnvVars
    </Directory>

    # MSIE 7 and newer should be able to use keepalive
    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

</VirtualHost>

The domain has been anonymized, of course.

Testing the URLs in the browser gives me:

monitor.mydomain.net -> Nagios page from monitor.mydomain.net
timetracker.mydomain.net -> ALSO the Nagios page from monitor.mydomain.net, while it is supposed to serve the Kimai page from timetracker.mydomain.net.

This is the log file nagios_acces.log after I access the page through monitor.mydomain.net:

 188.194.164.71 - nagiosadmin [10/Oct/2016:19:08:35 +0000] "GET / HTTP/1.1" 200 6389 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.0"
 188.194.164.71 - nagiosadmin [10/Oct/2016:19:08:36 +0000] "GET /side.php HTTP/1.1" 200 1429 "https://monitor.mydomain.net/" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.0"
 188.194.164.71 - nagiosadmin [10/Oct/2016:19:08:36 +0000] "GET /main.php HTTP/1.1" 200 1917 "https://monitor.mydomain.net/" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.0"

When I access the site through timetracker.mydomain.com, I get these lines in the same logfile:

188.194.164.71 - nagiosadmin [10/Oct/2016:19:12:19 +0000] "GET / HTTP/1.1" 200 1018 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.0"
188.194.164.71 - nagiosadmin [10/Oct/2016:19:12:20 +0000] "GET /side.php HTTP/1.1" 200 1429 "https://timetracker.mydomain.net/" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.0"
188.194.164.71 - nagiosadmin [10/Oct/2016:19:12:20 +0000] "GET /main.php HTTP/1.1" 200 1917 "https://timetracker.mydomain.net/" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.0"
188.194.164.71 - nagiosadmin [10/Oct/2016:19:12:20 +0000] "GET /images/favicon.ico HTTP/1.1" 200 1178 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0 Iceweasel/38.2.0"

Note that these lines also appear in the logfile for monitor; the actual logfile for timetracker stays empty.

Somebody suggested to me that Amazon EC2 instances might be behind a reverse proxy that somehow drops the host name to which the original HTTP request was made.

Is this true and if so, how can I work around it?

Thanks a lot in advance!

EDIT: This whole configuration has been migrated from another server where it was working perfectly as expected. The /etc/apache2 directories on both servers are completely identical, except for the 2nd level domain name of course. The only other difference is that the original server is Debian Jessie while the new server is Ubuntu 14.04.

Best Answer

It's because of network environment of AWS. Your EC2 instance looks like it has 2 IPs assigned (private one ane public one) but in reality EC2 has assigned only private ip. Public IP points into some huge NAT device which is in front of VPC and which knows how to map public IP to your EC2 instance. This is one of weirdness of AWS.

And this is root cause of your problem. As you can see, your default virtual host is declared as <VirtualHost *:80> or <VirtualHost *:443> which means for apache something like "scan requests on every interfaces where apache is listening and look for request with Host header equal of monitor.mydomain.net (as set in ServerName directive)". This is ok, your requests are comming thru your private IP (due that NAT device) and everything is working.

But in your second virtualhost, you have declared is as <VirtualHost timetracker.mydomain.net:80> resp. as <VirtualHost timetracker.mydomain.net:443>, which means in apache language "scan all requests comming thru interface with IP timetracker.mydomain.net and looks for Host header timetracker.mydomain.net". Problem is that your EC2 has no interface with IP of timetracker.mydomain.net because that IP points to AWS NAT device, not your EC2 instance, so this rule is never used.

You have to reconfigure all of your VirtualHosts to listen on *:80 and *:443 and just define your sites with ServerName directive. Unfortunatelly there is no way how you can have your public IP directly on your EC2. AWS has this because they want to dynamically change mapping of IPs and EC2 instances.

Related Topic