Here is a simple way to configure an OS-X system for web development. It allows one to develop multiple sites locally, without reconfiguring anything when changing sites/customers.
There are two key components to the strategy: dnsmasq and the httpd daemon's configuration.
dnsmasq will be used to handle domain name resolution for the sites under development. From the dnsmasq site:
Dnsmasq provides network infrastructure for small networks: DNS, DHCP, router advertisement and network boot. It is designed to be lightweight and have a small footprint, suitable for resource constrained routers and firewalls. It has also been widely used for tethering on smartphones and portable hotspots, and to support virtual networking in virtualisation frameworks.
I configure dnsmasq so that any domain name ending in .dev resolves to my local machine. For example, clientsite.com will resolve to the IP address of the client's site, which clientsite.com.dev will resolve to my local IP. I find that this arrangement make it quite simple to develop code locally and then deploy remotely.
Here are the steps:
Use macports to install dnsmasq. At the end of the installation, macports will emit a message about how to configure dnsmasq so that it is started automatically at boot time. Make a note of this for later use.
Configure dnsmasq so that any TLD ending in .dev TLD resolves to the local machine at 127.0.0.1.
Copy the example dnsmasq.conf configuration provided by macports to the correct location:
Update the configuration file to resolve .dev as described:
Use macports to configure launchd to start dnsmasq at boot time:
Test the configuration of your local DNS server (i.e., dnsmasq):
At this point, dnsmasq is working properly.
Configure DNS on OS-X
We now need to tweak OS-X so that it uses dnsmasq for name resolution. These instructions are valid for OS-X 10.11.6.
Use the 'System Preferences' application to modify the network settings:
Click Advanced on the network settings page. Click the DNS tab. I use Google's public DNS servers, I have two entries already: 184.108.40.206 and 220.127.116.11. You may have a different number of entries, including zero.
Under DNS Servers:, click the '+'. Type in 127.0.0.1. This will put 127.0.0.1 at the bottom of the list of DNS servers. However, we want 127.0.0.1 (i.e., dnsmasq) to be consulted first, before any other servers. Drag 127.0.0.1 up to the top of the list.
Click OK then Apply to save your changes.
After this, OS-X should send all DNS queries to dnsmasq first. If dnsmasq can't resolve the name, then it will move down the list. In my case, it will move onto 18.104.22.168 and 22.214.171.124.
Note that OS-X does not use /etc/resolv.conf to choose DNS servers. Do not edit the file -- it is generated automatically when System Preferences changes related information. It exists so that software which does use resolv.conf will continue to function properly.
Note also that there are other ways to configure dnsmasq. One alternate configuration directs OS-X to only query dnsmasq, thereby relying upon dnsmasq to query other servers as necessary.
I think that the configuration presented here is the simplest. And it does work, so it's got that going for it.
Test your new configuration. 'dig clientsite.com.dev' should resolve to 127.0.0.1 and 'dig clientsite.com' should resolve to the site's correct address.
You say you want to undo what you've done? Not a problem:
In System Preferences, go to network, advanced, DNS, select 127.0.0.1, then click the - to remove the entry. Click OK then Apply. Once this has been done, OS-X will no longer attempt to use dnsmasq to resolve host names.
After that, you'll want to do the following:
dnsmasq was configured with a scheme that can be used for any development site you work with -- there are no configuration changes when you add or remove sites. Let's configure Apache in the same manner.
We will create a new directory which will contain all sites. Under this directory there will be additional directories -- one for each site. These subdirectories can be added/removed at will.
# First setup the container directory $ sudo mkdir -p /www/sites # Make it mine $ ME=`whoami` sudo -E -s -- "chown -R $ME /www"
Let's setup two dummy sites for testing, one for customer foo.com and one for customer bar.com. The wwwroot directory of each will contain the directory structure for all of the files to be served for that site.
To configure Apache, you'll need to edit two configuration files. This is for 10.11.6, YMMV.
- Find the line that begins with #LoadModule and ends with mod_vhost_alias.so. Uncomment the line by removing the #. This will enable vhosts on your system.
- Find the line that begins with #Include and ends with httpd-vhosts.conf. Uncomment the line by removing the #. This tells Apache where to find the vhost configuration information.
- Save the changes.
Comment out the configuration that is present and add the following:
<Directory "/www"> Options Indexes MultiViews FollowSymLinks AllowOverride All Order allow,deny Allow from all Require all granted </Directory> <Virtualhost *:80> VirtualDocumentRoot "/www/home/wwwroot" ServerName home.dev UseCanonicalName Off </Virtualhost> <Virtualhost *:80> VirtualDocumentRoot "/www/sites/%1/wwwroot" ServerName sites.dev ServerAlias *.dev UseCanonicalName Off </Virtualhost>
Restart Apache so that it loads the new config: sudo apachectl restart.
Now, test your sites:
At this point, you can add and remove sites under /www with impunity, never having to reconfigure or restart anything again.
After writing the preceding, I wanted to do a similar thing, except running a Django WSGI application from a local repository while supporting SSL. This addendum covers that scenario.
The approach I took was to create a separate VHost configuration for the client. I simply included this configuration from httpd.conf. Here are the salient parts. Note that some of this content veers off into Django/WSGI content.
I created a httpd_macOS.conf file, which contained:
Note that instead of using /www as before, the above allows httpd to access files in my local directory structure, specifically the repo for a client. This is acceptable for local isolated development, but one should never do this on a server that is publicly accessible, as the security risk is large.
Since I was asked about it, here is a sample WSGI application (i.e., django.wsgi) that could be used with the above.
import os import sys # Update sys.path to include the Django application. Here is # how to do it relative to the location of the WSGI script. YMMV. wsgi_dir = os.path.dirname(__file__) app_dir = os.path.dirname(wsgi_dir) sys.path.append(os.path.join(app_dir, 'ecom')) sys.path.append(os.path.join(app_dir, 'ecom', 'store')) os.environ['DJANGO_SETTINGS_MODULE'] = 'store.settings' import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler()