4

I'd like to make a virtual host like this:

<VirtualHost *:80 *:443>
    <IfPort 443>
        SSLEngine On
        ...
    </IfPort>

    ...
</VirtualHost>

So, if the host has been accessed through port 443, I want to add some additional functionality. Can I achieve this somehow or do I have to separate this into 2 virtual hosts?

morgoth84
  • 161
  • 1
  • 1
  • 7
  • If it's just the one domain it's going to be a lot easier to just keep the two separate virtual host configurations. – Chris S Dec 30 '13 at 20:13
  • 1
    I think it would be best to just redirect http to https, avoiding the problem entirely. – Michael Hampton Dec 30 '13 at 20:39
  • But maybe there's no need to keep the whole site on HTTPS. You could have half the stuff on HTTP and half on HTTPS. And the web application would handle logic for redirects to the appropriate protocol. If all this is true, you'd still need two almost exactly the same virtual host configs. – morgoth84 Dec 30 '13 at 20:48

4 Answers4

4

I use mod_macro to solve this issue on a server that hosts a ton of different domains... Install the module (differs per OS/Distro), then configure something like this:

LoadModule macro_module         libexec/apache22/mod_macro.so

<Macro VHost $host>
        <VirtualHost *:80>
                DocumentRoot /usr/local/www/$host/data
                ServerName $host
                ServerAlias *.$host

                ScriptAlias /cgi-bin/ "/usr/local/www/$host/cgi-bin/"
                IncludeOptional etc/apache22/vhosts/$host
        </VirtualHost> 
</Macro>

<Macro VHostSSL $host>
        <VirtualHost *:80>
                DocumentRoot /usr/local/www/$host/data
                ServerName $host
                ServerAlias *.$host

                ScriptAlias /cgi-bin/ "/usr/local/www/$host/cgi-bin/"
                IncludeOptional etc/apache22/vhosts/$host
        </VirtualHost>
        <VirtualHost *:443>
                DocumentRoot /usr/local/www/$host/data
                ServerName $host
                ServerAlias *.$host

                SSLEngine on
                SSLCertificateFile /usr/local/www/$host/ssl/$host.crt
                SSLCertificateKeyFile /usr/local/www/$host/ssl/$host.key

                ScriptAlias /cgi-bin/ "/usr/local/www/$host/cgi-bin/"
                IncludeOptional etc/apache22/vhosts/$host
        </VirtualHost> 
</Macro>

Use VHostSSL example.com 
Use VHost    example.net

Super easy to add a new domain; any domain specific configurations get tossed in the include file.

Chris S
  • 77,337
  • 11
  • 120
  • 212
2

using John's solution i get this

Apache 2 is starting ...
AH00526: Syntax error on line 53 of .../httpd-vhosts.conf:
SSLEngine not allowed here

as John said,the best way is to have 2 virtual hosts ;but my virtual host code was more than 150 lines (lots of reverse proxies) as i didn't want to have 2 of each code (and a very long config file) i ended up doing this which works:

1.Create a virtual host for non-ssl virtual host.

2.Create another virtual host and reverse proxy to the first virtual host

<VirtualHost *:443>
    SSLEngine on
    SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
    SSLCertificateFile "...cert.crt"
    SSLCertificateKeyFile "...server.ssl.key"
    ... (any ssl specific config)

    ProxyPreserveHost On
    ProxyPass / http://localhost:80/
    ProxyPassReverse http://localhost:80/ http://yourdomain.com/
</VirtualHost>

this is not at all a good or performance friendly solution but if the reason behind not wanting 2 virtual hosts is to prevent having 2 verions of all virtual host configs (which means changing 2 lines each time you want to change something) this works.

Bor691
  • 213
  • 4
  • 14
2

Another option to avoid duplication would be to keep the virtualhost config in a specific file, and pull it in with an include:

/etc/path/to/config/example.com.conf:

ServerName example.com.conf
DocumentRoot /var/www/something
# Any other config you want to apply to both vhosts

And your virtual hosts file:

<VirtualHost *:443>
    SSLEngine on
    # Other SSL directives
    Include /etc/path/to/config/example.com.conf
</VirtualHost>
<VirtualHost *:80>
    Include /etc/path/to/config/example.com.conf
</VirtualHost>
Shane Madden
  • 112,982
  • 12
  • 174
  • 248
  • This is quite nice, but I'd still like to have 1 file for 1 web side configuration. This way I still need at least 2 files. Or maybe one master file with all virtual hosts and a series of these include files for each web site. (I'd upvote your answer, but I don't have enought rep. :/) – morgoth84 Dec 30 '13 at 19:42
  • @morgoth84 Right, you can do one large virtual host file and an included file for each site. I'd say check out a configuration management system to manage this if doing it manually is going to be too much of a headache! – Shane Madden Dec 30 '13 at 20:38
1

Have a look at the Apache If structure, and manipulate the request. See the core documentation for Ifs and the list of available expressions to use in it. You could do something like :

<If "%{SERVER_PORT} == '443'">
    # Do stuff
</If>

Concerning your VirtualHost tag, I don't see such solution in the Apache2 documentation. See http://httpd.apache.org/docs/2.2/en/vhosts/examples.html#port and try your option : Apache2 uses a similar one for different IPs instead of different ports (http://httpd.apache.org/docs/2.2/en/vhosts/examples.html#intraextra).

I would still recommend the use of 2 distinct virtual hosts, much clearer. You will need two NameVirtualHost and Listen in your apache2.conf file, anyway.

Edit

I did not realise this solution actually threw an error, but let's go back to the concept itself... Listening on 80 or 443 in no problem actually. Apache2 would gladly provide an elegant solution for that, if it wasn't for... encryption. Apache2 was developed in C, and beyond threads and forks, it uses sockets. In C, using SSL requires the initialisation of OpenSSL components, and some work around the basic socket to implement the whole SSL thing. You're looking for an easy solution, but the whole mechanism behind is tricky... That's why you can't enable SSL in a basic virtualhost : HTTP and HTTPs are different components, and in the Apache2 way, I'm afraid there's no concept of inheritance between the first and the second.

ThoriumBR
  • 5,272
  • 2
  • 23
  • 34
John WH Smith
  • 341
  • 4
  • 18
  • This would be a really elegant solution, but unfortunately, as @Bor691 stated, it throws `SSLEngine not allowed here`. :/ I don't like 2 separate virtual hosts because it's basically one web site, one entity so it should have one definition. – morgoth84 Dec 30 '13 at 19:39
  • I'm afraid it's only logical... Listening on 80 and 443 is not the problem, but through an HTTP virtual host, data flows in clear, meanwhile it takes encryption to communicate through HTTPS. The request handling process has a whole additional layout. – John WH Smith Dec 30 '13 at 19:44
  • When you put it that way, it's obvious that something like this isn't possible, at least not with the current version. But they could still implement an `if` like this in a future version. And if the `if` is present in a virtual host configuration, they could internally split the configuration into 2 separate instances, one with the `if` contents, and one without. You'd basically have one virtual host configuration, but Apache would see it as two. – morgoth84 Dec 30 '13 at 20:00
  • This would require Apache to create an abstraction level for something that already exists concretely : `VirtualHosts`. This would allow *virtual hosts into virtual hosts*, which doesn't mean anything, as a host shall always be an IP address (and in the Apache way, an IP-port duo). It would be easier in your case, but would probably cause some illogical situations to occur in a basic setup ^^ – John WH Smith Dec 30 '13 at 20:04
  • Yeah, main problem with `` is "Only directives that support the directory context can be used within this configuration section." http://httpd.apache.org/docs/2.4/mod/core.html#if – lkraav Mar 18 '17 at 12:29