Docker - Run Apache on host and container for different websites

16,021

Solution 1

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.

Solution 2

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.

Share:
16,021

Related videos on Youtube

AntoineB
Author by

AntoineB

Read my blog about programming, mindflash.org. A few sample articles: Top things to learn for a beginner programmer One day in the life of a professional software engineer And also tutorials on specific topics, sometimes coming from the content of my StackOverflow questions & answers!

Updated on September 15, 2022

Comments

  • AntoineB
    AntoineB over 1 year

    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 :

    Representation of my architecture

    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 :)

  • AntoineB
    AntoineB over 8 years
    Thanks, I've used a reverse proxy but actually created 3 containers, one for each Apache / PHP combo, and one for nginx, which seems better :)
  • VonC
    VonC over 8 years
    Good choice. One service per container remains the best practice.