1

Visualize this outcome:

  1. site1.example.com -> my single public IP -> Port forwarding 80 and 443 to LAN 192.168.1.10 Mac running OS X Server 4.1 on OS X 10.10 Yosemite
  2. site2.example.com -> my single public IP -> LAN 192.168.1.10 -> reverse proxy? -> :80 and :443 on LAN 192.168.1.15

This is on a network where I have no option of adding another public IP.

#1 is already up and running fine.

#2 is the hard part, mainly because I'm running OS X Server on #1, and the proxy setup does not seem to be the relatively straight-forward Apache one, e.g.:

<VirtualHost *:80 *:443>
     ServerName site2.example.com

     ProxyRequests off
     ProxyPass / http://192.168.1.15/
     ProxyPassReverse / http://192.168.1.15/
</VirtualHost>

That is, OS X Server has the Apache config files in odd places, and my understanding is that it likes to overwrite them with new changes made in the GUI, so I'm trying to figure out the “right” way to do this on OS X Server.

A friend of mine suggested there might be a way to do it with OS X Server's webappctl command and writing an appropriate webapp.plist, though the Work with web apps section of the OS X Server docs contains almost no detail. Looking at the man pages Apple suggests and their example .plist file, it seems to me that their idea of a “web app” really wants to be attached to a directory (i.e., site1.example.com/webapp), and not as a subdomain (as in #2, above). Perhaps I just haven't quite figured out the .plist formatting yet?

What is the “right” way to do this on OS X Server?

swizzlevixen
  • 111
  • 5
  • I don't know the answer to your question, because I don't use OS X Server. Very few people here do, so unfortunately you're unlikely to get an answer. Sorry. But meanwhile we do have standards for how questions should be written and it helps the site overall to maintain them. – Andrew Schulman May 13 '15 at 01:01
  • Also, questions about home networks are [off-topic](http://serverfault.com/help/on-topic) here. – Andrew Schulman May 13 '15 at 01:06
  • Editing your question isn't "singling you out". It's improving the question, and is a basic feature of all Stack Exchange sites. – Andrew Schulman May 13 '15 at 01:34

2 Answers2

0

I think your friend might be on to something with the webappctl path. But let's start from Apache: when using OS X Server, Apache pulls its configuration from /Library/Server/Web/Config/apache2. That directory contains a file ReadMe.txt, which says in part:

sites/

This directory contains a file for each enabled virtual host configured for Websites Service by the Server application. Its contents are read by Apache due to several "Include" directives in httpd_server_app.conf.

...

These files are modified by the server-resident part of the Server application and by webappctl(8). Administrators may make changes directly to this file, and to custom virtual host files, but it's strongly recommended that administrator put changes in separate "Include" files and use the webapp.plist(8) mechanism in conjunction with the webappctl(8) command-line tool to manage them. See the editing guidelines at the top of those files.

OK, seems reasonable. Looking further inside that Apache config directory, there's the referenced sites subdirectory, as well as webapps. The latter contains a bunch of plists describing OS X Server's Web services, plus one named com.example.mywebapp.plist. Right up at the top of that file, there are a few bits of interest:

  • The includeFiles key, which looks to have an array of paths to custom include .conf files that the webapp wants
  • The proxies key, which maps to Apache ProxyPass/ProxyPassReverse directives for another app

While I haven't tested this myself, my suggestion might be to try adding a plist to this directory yourself using the same reverse-DNS naming scheme: copy com.example.mywebapp.plist to com.example.site2.plist. Once you have your own copy, you can chop out most of the unnecessary bits, then tweak the proxies value to refer to your own URL instead of the example path they have.

If that doesn't work, you could apply a slightly bigger hammer and create an includable .conf file that has your straightforward Apache directives from the question in it, placing it inside Server's Apache config directory. Once that's done, drop the proxies key from your webapp plist altogether, and instead use the includeFiles key to pull in that .conf file.

Either way, once the webapp plist is in place, use webappctl (as root) to start the newly created app:

$ sudo webappctl start com.example.site2

That should either succeed (returning exit code 0) or – hopefully – fail with some information that you can refine the webapp plist with. (Again, this is all untested, and is just a point to start from.)

If you do wind up using a custom included .conf file that you reference from the webapp plist, it's also not a bad idea to keep a backup of that file somewhere, so that future OS X or Server.app updates don't erase it. While Server's Apache ReadMe.txt doesn't explicitly say that they will erase user-generated configurations, it doesn't say they won't, either. Better safe than sorry.

Good luck!

Tim
  • 1,158
  • 1
  • 14
  • 23
  • Tried just adding the .plist, but no go, and it also seemed to make OS X Server freak out, giving me 503 errors on all web services. when I removed the .plist and restarted services, it still was giving me 503s, so I reverted to the initial configuration with a Time Machine backup. Will try again next week. – swizzlevixen May 14 '15 at 19:21
0

This question was originally asked about Mac OS X Server 4.1, but as software version numbers have moved on, and I just now got this working, this answer is written as of macOS Server 5.2. Server 5 apparently changes things a bit in that every service in Server is now behind one master reverse proxy, so these instructions will not work with Server 4.1.

Configuration Files

Make web app configuration file on the macOS Server machine, in /Library/Server/Web/Config/apache2/httpd_site2webapp.conf, pointing at the IP address of the site2 server.

ProxyPreserveHost On
ProxyPassReverse / http://192.168.1.15:80/
ProxyPass / http://192.168.1.15:80/
ServerName site2.example.com

Then in /Library/Server/Web/Config/apache2/webapps/com.example.site2webapp.plist, add the following, referencing the location of the .conf file above:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<!-- See man pages for webapp.plist(5) and webappctl(8) for information about this example webapp.plist -->

<plist version="1.0">
    <dict>
        <key>includeFiles</key>
            <array> <!-- Include files are activated in virtual host when webapp is started -->
                <string>/Library/Server/Web/Config/apache2/httpd_site2webapp.conf</string>
            </array>
        <key>name</key>
            <string>com.example.site2webapp</string>
        <key>displayName</key> <!-- Name shown in Server app -->
            <string>site2WebApp</string>
        <key>installationIndicatorFilePath</key> <!-- The presence of this file indicates web app is installed -->
            <string>/Library/Server/Web/Config/apache2/httpd_site2webapp.conf</string>
        <key>sslPolicy</key><!-- Determines webapp SSL behavior -->
            <integer>0</integer> <!-- 0: default, UseSSLWhenEnabled -->
                                 <!-- 1: UseSSLAlways -->
                                 <!-- 2: UseSSLOnlyWhenCertificateIsTrustable -->
                                 <!-- 3: UseSSLNever -->
                                 <!-- 4: UseSSLAndNonSSL -->
    </dict>
</plist>

If you also need SSL, also put the following in /Library/Server/Web/Config/apache2/httpd_site2SSLwebapp.conf. The config differs in that LAN traffic between the servers will be unencrypted by default (this config essentially tells Server not to check if there is a valid cert), but the WAN traffic will be encrypted. I believe you can install a self-signed certificate on the site2 server for encrypted local traffic, but this config will still enable the reverse proxy without having to have matching certificates. (I grant there is likely a more correct way to secure the local traffic, but this worked for me.)

SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
ProxyPreserveHost On
ProxyPassReverse / http://192.168.1.15:80/
ProxyPass / http://192.168.1.15:80/
ServerName site2.example.com

And the corresponding SSL web app plist, /Library/Server/Web/Config/apache2/webapps/com.example.site2SSLwebapp.plist, much the same as above:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<!-- See man pages for webapp.plist(5) and webappctl(8) for information about this example webapp.plist -->

<plist version="1.0">
    <dict>
        <key>includeFiles</key>
            <array> <!-- Include files are activated in virtual host when webapp is started -->
                <string>/Library/Server/Web/Config/apache2/httpd_site2SSLwebapp.conf</string>
            </array>
        <key>name</key>
            <string>com.example.site2SSLwebapp</string>
        <key>displayName</key> <!-- Name shown in Server app -->
            <string>site2SSLWebApp</string>
        <key>installationIndicatorFilePath</key> <!-- The presence of this file indicates web app is installed -->
            <string>/Library/Server/Web/Config/apache2/httpd_site2SSLwebapp.conf</string>
        <key>sslPolicy</key><!-- Determines webapp SSL behavior -->
            <integer>0</integer> <!-- 0: default, UseSSLWhenEnabled -->
                                 <!-- 1: UseSSLAlways -->
                                 <!-- 2: UseSSLOnlyWhenCertificateIsTrustable -->
                                 <!-- 3: UseSSLNever -->
                                 <!-- 4: UseSSLAndNonSSL -->
    </dict>
</plist>

For each of these four files, the permissions need to be owner: root and group: wheel, 644:

$ sudo chown -R root:wheel /path/to/file
$ sudo chmod -R 644 /path/to/file

Setting up Server.app

Add the web app to Websites

  • In the Websites tab of the Server.app interface, click the + below the Websites listing to add a new site
  • Enter site2.example.com for Domain Name
  • Leave everything else at the default settings
  • Click Edit Advanced Settings…
  • Under the section “Make these web apps available on this website:” check Enable for site2WebApp
  • Click OK
  • Click Create

SSL

If you need SSL on the WAN, install a certificate in Server that covers the new domain. I used Let’s Encrypt to create a single certificate that was good for both my site1 and site2 domains.

  • In the Certificates tab of Server.app, click the + at the bottom of the window, then Import a Certificate Identity…
  • Drag-and-drop the .pem files you got back from Let's Encrypt (or whatever certificate files you have), and click Import
  • In the Websites tab, create the new site almost the same as before, except change the Port to 443 and under SSL Certificate, pick the cert you just imported
  • Under Edit Advanced Settings…, instead check Enable for site2SSLWebApp

My answer above is adapted from the instructions found at https://www.precursor.ca/precursor/resources/rais/landing/ReverseProxyTutorial.html. Warning: this link downloads a zip file with PDF and sample Server web app config files. Their zip also includes historical instructions for doing this with Server 4.1.

swizzlevixen
  • 111
  • 5