This repository contains configuration files to run nginx or apache containers(with MySQL & PHP support) behind Docker nginx-proxy which automates nginx proxy for Docker containers using docker-gen.
I work on many PHP based applications & websites and I needed a way to be able to customize each "container" instead of having to rely on a single server instance that is shared. The setup described here allows me to run virtual hosting that I can individually customize & tweak. The two examples provided under skeletons
directory should get you started with a fairly common webserver setup and give you the flexibility to tweak to suit your needs. MySQL Server is always needed and hence it is started when the nginx-proxy
container runs. Database directory is mounted from the Host side so that the data persists even after the container shuts down. (see _common/database
) It is still strongly recommneded to make backups of the directory as well as perform database dumps.
I am using this setup for developing things locally. I do not recommend using this for production at all.
Note: This guide is based on OS X as the Docker Host.
- Ensure no other programs are listening on port 80, 443, 3306 on the host machine.
- Install & run Docker Community Edition.
- Modify Host Database by adding some entries to hosts file.
e.g. /etc/hosts
127.0.0.1 db
,127.0.0.1 apache.dev
and127.0.0.1 nginx.dev
- Run this command once:
$ docker network create service-tier;
- Clone this repo into a centralized location to host all our containerized virtual host apps:
e.g. /Users/tonykwon/Sites
We will first run containers base off of our main compose file so that we have working nginx-proxy and MariaDB. Since we are pulling from official images, no images will be built locally.
$ cd /Users/tonykwon/Sites/_common
$ docker-compose up
Once the build (pulling of images really) is complete, check the images on a different terminal:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jwilder/nginx-proxy latest ca6685ed24ba 8 days ago 188MB
mariadb latest f04960029149 8 days ago 395MB
Also, check to see what containers are created & running.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9197af281717 jwilder/nginx-proxy "/app/docker-entry..." 2 seconds ago Up 1 second 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-proxy
360df1662580 mariadb "docker-entrypoint..." 2 seconds ago Up 1 second 0.0.0.0:3306->3306/tcp db
To stop, press ctrl+c then $ docker-compose down
Gracefully stopping... (press Ctrl+C again to force)
Stopping nginx-proxy ... done
Stopping db ... done
$ docker-compose down
Removing nginx-proxy ... done
Removing db ... done
Network service-tier is external, skipping
Double check to ensure no containers are running:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Now, we need the main containers up and running again.
$ cd /Users/tonykwon/_common
$ docker-compose up (to run on the foreground)
or
$ docker-compose up -d (to run on the background)
Then on a different terminal, run:
$ cd /Users/tonykwon/_common/skeletons/apache.dev/
$ docker-compose up (initial build could take a long time)
Try visiting http://apache.dev/
on a browser to ensure the containers are up and running. Also check to see what images are pulled/created:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
apachedev_web latest b703da15d542 2 minutes ago 97.8MB
apachedev_app latest 3397e3bf030c 2 minutes ago 149MB
php fpm-alpine 56ed8b111665 6 hours ago 68.6MB
httpd alpine a3ef8c72123c 25 hours ago 94.8MB
jwilder/nginx-proxy latest ca6685ed24ba 8 days ago 188MB
mariadb latest f04960029149 8 days ago 395MB
$ cd /Users/tonykwon/_common/skeletons/nginx.dev/
$ docker-compose up
Try visiting http://nginx.dev/
on a browser to ensure the containers are up and running. Similarly, check to see what images are pulled/created by running $ docker images
command.
We need the nginx-proxy & database containers running while we are working so on the main terminal we run:
$ cd /Users/tonykwon/Sites/_common
$ docker-compose up (to run on the foreground)
or
$ docker-compose up -d (to run on the background)
e.g. Your new site you want to work on is test.dev
- Add
127.0.0.1 test.dev
to your hosts file. - Create a directory named
test.dev
under/Users/tonykwon/Sites
. - Pick a skeleton from
_common/skeletons
directory then copy the content intotest.dev
directory. - Open
docker-compose.yml
file and make necessary adjustments: volumes(document root to match the virtual host name), environment(VIRTUAL_HOST, DOCUMENT_ROOT). - Review the content of
__Docker
directory and make necessary adjustments e.g.php.ini
andwww.conf
- Move to the top level directory:
$ cd /Users/tonykwon/Sites/test.dev
- build & run:
$ docker-compose up
- Once you are done with
test.dev
(ctrl+c to halt) then$ docker-compose down
NOTE
- To reach the database server from the Docker Host, (e.g. using Sequel Pro) use
127.0.0.1
,Username: root
,Password: password
- To reach the database server from the container, use
db
as hostname
Sites/
_common
database -> mapped to /var/lib/mysql of database container
certs -> ssl certificates
skeletons -> 2 example configurations
vhost.d -> mapped to /etc/nginx/vhost.d of the nginx proxy which listens on 80, 443
docker-compose.yml
Sites/_common/skeletons
apache.dev -> apache example
__Docker
app.dockerfile -> Dockerfile that builds php-fpm
web.dockerfile -> Dockerfile that builds apache
vhost.conf -> VirtualHost configuration for apache
php.ini -> Custom php.ini configuration
www.conf -> Custom php-fpm configuration
docker-compose.yml
webroot -> webroot
index.html
index.php
nginx.dev -> nginx example
__Docker
app.dockerfile -> Dockerfile that builds php-fpm
web.dockerfile -> Dockerfile that builds nginx
vhost.conf -> Virtualhost configuration for nginx
php.ini -> Custom php.ini configuration
www.conf -> Custom php-fpm configuration
docker-compose.yml
webroot -> webroot
index.html
index.php
php.dev -> stand-alone PHP example
__Docker
app.dockerfile -> Dockerfile that builds php
app-zts.dockerfile -> Dockerfile that builds php w/ ZTS support
php.ini -> Custom php.ini configuration
docker-compose.yml
webroot -> webroot
index.php
Say you want some SSL support for VIRTUAL_HOST ssl.dev
per se using self-signed ssl certificate. The default setup redirects all non-ssl traffic to ssl then assumes the SSL backend is non-ssl (which works perfect in our setup as we do not need to touch the existing vhost.conf)
NOTE: In order to get around some side effects with nginx-proxy SSL support, two environment variables are set on all skeleton containers: CERT_NAME
and HTTPS_METHOD
. By adding following variables, we ensure that HTTPS is disabled by default. To enable, first comment out the two environment variables then follow the instructions below.
CERT_NAME: {VIRTUAL_HOST}.dev # comment out to support SSL
HTTPS_METHOD: nohttps # comment out to support SSL
- Move to the common certs directory.
$ cd /Users/tonykwon/Sites/_common/certs
- Generate self-signed key and certificate pair in one go for
ssl.dev
.$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ssl.dev.key -out ssl.dev.crt
Note:-keyout
and-out
names:{VIRTUAL_HOST}.key
and{VIRTUAL_HOST}.crt
- When generating certificates, ensure you use the Common Name as
ssl.dev
. It is possible to generate a default certificate that serves all top-level domains, but as far as I know there are some browsers that DO NOT supportwildcard domains
at the top-level. In order to use the wildcard domains, I believe you need to use a base domain name such asmyapps.dev
and virtual host names likeapache.myapps.dev
,nginx.myapps.dev
,ssl.myapps.dev
and so on. So in this case, default certificate can have the Common Name*.myapps.dev
and the file names can bedefault.key
anddefault.crt
. - Restart the nginx-proxy container.
- Restart the virtual host container.
NOTE: Because we are treating the backend non-ssl, there is nothing to modify on the virtual host container side. If the SSL Backend must support SSL, supply VIRTUAL_PROTO=https
, VIRTUAL_PORT=443
and HTTPS_METHOD=nohttp
to the environment but this requires you to modify vhost.conf which I will not cover here.
NOTE: Because we are using self-signed certificates, you'd normally go through to add an exception as shown here..