wrt the issues above:
- Yes you can. Very effectively. Just be aware that your Django sites won't integrate into Server App's GUI unless you restrict yourself to python 2.7; Apache mod_wsgi; no virtualenvs.
- Not if you wish to proxy to a wsgi server like Gunicorn, because when you save the Website's panel, OS X Server will sanitise some of your essential Apache directives and you will lose control over how your Django static files, for example, are served. OS X Server has a particular execution and configuration model in mind and it does a good job of managing websites that accord with that model - but at the cost of flexibility. I know that people successully deploy Django using Apache's mod_wsgi, but that comes with severe limitations.
- As in 2. The
proxies
section of the plist for your web app in OS X Server's ../apache2/webapp
directory is all-or-nothing. e.g. You can't Include a ProxyPass /static/ !
in the right place for it to have effect.
- Not with Apache mod_wsgi.
- No. OS X Server 3.2.1 uses Apache 2.2. Proxies via UDS was not included in Apache until later. (Perhaps you could have Apache proxy to Nginx (via a TCP port) and, in turn, proxying to Gunicorn via each Django site's own UDS ... if you thought there was a compelling reason.)
- Yes.
The approach I took:
- Put your application's Apache
.conf
file in OS X Server's ../apache2/other
directory where it will be left alone by the Server app.
- Forget about trying to use the Server GUI and 'binding' web apps to sites through its Advanced settings window. A nice idea but ...
- Use virtualenv(wrapper) to set up the different python and package versions for a more future-proof approach ... OS X Server 4 on Yosemite coming up!
Example code:
.conf for Django virtual server
This is adapted directly from the file that OS X Server generates from its GUI with these main differences:
ProxyPreserveHost
is off by default.
ProxyPass /static/ !
prevents the Alias directive from being ignored. I found that, when including this directive using the Apple-recommended web app .plist includeFiles
section, the Included lines were in the wrong place to have the desired effect.
sed
your SITENAME and PORT:
<VirtualHost *:80>
ServerName SITENAME
ServerAdmin mail@you.com
DocumentRoot "/usr/local/python_projects/SITENAME"
ErrorLog /var/log/apache2/error_log
<IfModule mod_ssl.c>
SSLEngine Off
SSLCipherSuite "ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM"
SSLProtocol -ALL +SSLv3 +TLSv1
SSLProxyEngine On
SSLProxyProtocol -ALL +SSLv3 +TLSv1
</IfModule>
<Directory "/usr/local/python_projects/SITENAME">
Options All -Indexes -ExecCGI -Includes +MultiViews
AllowOverride None
<IfModule mod_dav.c>
DAV Off
</IfModule>
</Directory>
ProxyPass /static/ !
Alias /static/ /usr/local/python_projects/SITENAME/static/
ProxyPass / http://localhost:PORT/
ProxyPassReverse / http://localhost:PORT/
ProxyPreserveHost On
</VirtualHost>
LaunchDaemon plist for Gunicorn wsgi server
sed
your SITENAME; REVERSED_SITENAME and PORT:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Label</key>
<string>REVERSED_SITENAME</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/virtualenvs/SITENAME/bin/gunicorn</string>
<string>--bind=127.0.0.1:PORT</string>
<string>--workers=2</string>
<string>superlists.wsgi:application</string>
</array>
<key>RunAtLoad</key><true/>
<key>WorkingDirectory</key><string>/usr/local/python_projects/SITENAME/source</string>
<!-- <key>StandardErrorPath</key><string>/var/log/gunicorn/REVERSED_SITENAME.error.log</string> -->
<key>KeepAlive</key><true/>
</dict>
</plist>
Snippet from the OS X Server's .bash_exports
Shows virtualenv paths specified by the virtualenvwrapper environment variables
export WORKON_HOME=/usr/local/virtualenvs
export PROJECT_HOME=/usr/local/python_projects
export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3
export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/bin/virtualenv
source /usr/local/bin/virtualenvwrapper.sh
Snippet from the Fabric automation file fabfile.py
Shows:
The target paths - the directories where your configuration files will end up;
The commands to activate the Django site in the final steps in deployment
# copy (and overwrite if necssary) configuration files to the LaunchDaemons and apache2/sitesdirectories
sudo('cp -f %s /Library/LaunchDaemons/%s.plist' % (gunicorn_config_file, reversed_site_name))
sudo('cp -f %s /Library/Server/Web/Config/apache2/other/%s.conf' % (apache2_config_file, site_name))
# Get the gunicorn wsgi server running on its unique TCP port
sudo('launchctl unload -w /Library/LaunchDaemons/%s.plist' % (reversed_site_name,), warn_only=True)
sudo('launchctl load -w /Library/LaunchDaemons/%s.plist' % (reversed_site_name,))
# Give us some assurance that the gunicorn port is open
sudo('lsof -i TCP:%s' % (port,))
# Get Apache to include the new website; talk to gunicorn; and make it available to he world!
sudo('apache2ctl graceful')