I want to use Docker in order to be able to run an old application that requires PHP 5.3, while still having my other websites on my host server, running on the host Apache.
So I have siteA.com, siteB.com, siteC.com running on the host, using the host Apache / PHP / MySQL server, and I have siteZ.com that is installed in a Docker container, which should be using the container's Apache / PHP but the host MySQL server.
Here's a representation of the architecture I'd like to obtain :
My issue is that it seems like I can't run Apache in the container, since the port 80 is already in use on the host.
My goal would be that the people could access siteA.com, siteB.com, siteC.com and siteZ.com, without having to specify a different port for any of those websites.
I managed to get siteZ.com running by using port 8080, but it's obviously not an option.
Thanks
PS : Please note that I'm completly new to Docker.
Edit : You can find my working solution here. Thanks to VonC for showing me the way to go :)
Thanks to VonC's answer I managed to get it working but I slightly changed my architecture, resulting in 3 containers instead of only 1.
I have one container for each Apache / PHP version, and one container with Nginx as reverse proxy. I think you can easily adapt this to install Nginx on the host and change it's configuration to match the architecture I described in my question.
Note that as I'm new to Docker, and a noob regarding Linux system administration, there's probably some mistakes and things that don't make any sense in the following scripts, but it's working for me. Feel free to improve it :)
Nginx Reverse Proxy image
The Dockerfile :
FROM debian:jessie
MAINTAINER AntoineB version: 0.1
RUN apt-get update && \
apt-get install -y --force-yes \
nginx \
nano
EXPOSE 80
EXPOSE 443
ADD ./proxy.conf /etc/nginx/conf.d/proxy.conf
CMD ["nginx"]
Here's the referenced proxy.conf
file :
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
client_header_buffer_size 64k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 16k;
proxy_buffers 32 16k;
proxy_busy_buffers_size 64k;
And I run it using the following bash script :
docker run -ti -d -p 80:80 -v /home/antoineb/Docker/images/nginxproxy/virtualhosts:/etc/nginx/sites-enabled --name nginxproxy nginxproxy /bin/bash
I have a /home/antoineb/Docker/images/nginxproxy/virtualhosts
folder on my host that contains the following default
file :
server {
listen 80;
server_name siteZ.com;
location / {
proxy_pass http://apache22php53:80;
}
}
server {
listen 80;
server_name siteA.com;
location / {
proxy_pass http://apache24php56:80;
}
}
server {
listen 80;
server_name siteB.com;
location / {
proxy_pass http://apache24php56:80;
}
}
Apache 2.2 + PHP 5.3 image
Dockerfile :
FROM debian:wheezy
MAINTAINER AntoineB version: 0.1
RUN apt-get update
RUN echo "deb http://packages.dotdeb.org squeeze all" > /etc/apt/sources.list.d/dotdeb_squeeze.list
RUN echo "deb-src http://packages.dotdeb.org squeeze all" >> /etc/apt/sources.list.d/dotdeb_squeeze.list
RUN echo "deb http://ftp.debian.org/debian/ squeeze main contrib non-free" >> /etc/apt/sources.list.d/dotdeb_squeeze.list
RUN echo "Package: *php*" > /etc/apt/preferences.d/php53.pref
RUN echo "Pin: release o=packages.dotdeb.org,n=squeeze" >> /etc/apt/preferences.d/php53.pref
RUN echo "Pin-Priority: 989" >> /etc/apt/preferences.d/php53.pref
RUN apt-get update && \
apt-get install -y --force-yes \
apache2 \
php5 \
php5-curl \
php5-gd \
php5-mysql \
nano
RUN a2enmod \
php5 \
rewrite
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
EXPOSE 80
EXPOSE 443
CMD /usr/sbin/apache2ctl -D FOREGROUND
I'm launching it using the following script :
docker run -ti -d -p 2253:80 -v /home:/home -v /home/antoineb/Docker/images/apache22php53/virtualhosts:/etc/apache2/sites-enabled --name apache22php53 apache22php53 /bin/bash
My websites are stored in /home/website.com/www, and my apache virtualhosts are stored on the host in /home/antoineb/Docker/images/apache22php53/virtualhosts
.
Apache 2.4 + PHP 5.6.9 image
Dockerfile :
FROM debian:jessie
MAINTAINER AntoineB version: 0.1
RUN apt-get update && \
apt-get install -y --force-yes \
apache2 \
php5 \
php5-curl \
php5-gd \
php5-mysql \
nano
RUN a2enmod \
php5 \
rewrite
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
EXPOSE 80
EXPOSE 443
CMD /usr/sbin/apache2ctl -D FOREGROUND
My running script :
docker run -ti -d -p 2456:80 -v /home:/home -v /home/antoineb/Docker/images/apache24php56/virtualhosts:/etc/apache2/sites-enabled --name apache24php56 apache24php56 /bin/bash
Again, my websites are stored in /home/website.com/www, and my apache virtualhosts are stored on the host in /home/antoineb/Docker/images/apache24php56/virtualhosts
.
I can't run Apache in the container, since the port 80 is already in use on the host.
Sure you can: in a container, you can run Apache on any port you want.
but when you do docker
run
, then you need to map this container port to a host port (which won't be 80, since it is already taken, but for instance 8080
docker run -d -p 8080:80 yourImage
My goal would be that the people could access siteA.com, siteB.com, siteC.com and siteZ.com
That is called reverse proxy, and you could run on port 80 a NGiNX (in a container or not) which would then reverse proxy back to siteA, B or C (each running on different port, in container or not).
See for instance "Nginx reverse proxy with multiple ssl domain".
Your main Apache wouldn't run directly on port 80 anymore (or it could, if you put it in a container!)
The goal behind putting everything in its own container is isolation.
Not just filesystem isolation with chroot, or memory isolation, but also configuration isolation: in a container, an Apache always run (if you want) in 80/443, not matter how many Apache containers are running.
You just launch them with the proper host port mapping, but inside a container, the config remains fixed and identical.
You can use host-based routing in docker glue
https://github.com/muayyad-alsadi/docker-glue
it's a light-weight daemon that generates haproxy
templates on the fly (you can define nginx template if you like) that watch container labels like this
docker run -d --name wp1 -l glue_http_80_host='wp1.example.com' mywordpress/wordpress
docker run -d --name wp2 -l glue_http_80_host='wp2.example.com' mywordpress/wordpress
in this setup the glue daemon will generate haproxy config so that traffic to wp1.example.com goes to wp1 container