Apache HTTP Server Docker Image - Cleaner configuration in Dockerfile wanted - apache

I have this Dockerfile that does extra configuration of the official Apache HTTP Server Docker image. Is there a cleaner way to do this inside a Dockerfile? I'm very unfamiliar with Apache HTTP Server configuration and was just about able to cobble this together. (The reason for enabling mod_rewrite is because I use it in a .htaccess file in the htdocs folder)
ARG BUILD_DIR=/usr/src/app
FROM node:10.13.0-alpine as build
ARG BUILD_DIR
WORKDIR $BUILD_DIR
COPY package.json .
RUN npm install
COPY src src
COPY public public
RUN npm run build
FROM httpd:2.4.37-alpine
ARG BUILD_DIR
ENV SERVER_CONTAINER_NAME=server
COPY --from=build $BUILD_DIR/build htdocs
RUN sed -i 's,#\(LoadModule rewrite_module modules/mod_rewrite.so\),\1,g' conf/httpd.conf \
&& sed -i -e '/<Directory "\/usr\/local\/apache2\/htdocs">/,/<\/Directory>/{s/AllowOverride None/AllowOverride All/}' conf/httpd.conf \
&& sed -i 's,#\(LoadModule proxy_module modules/mod_proxy.so\),\1,g' conf/httpd.conf \
&& sed -i 's,#\(LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so\),\1,g' conf/httpd.conf \
&& echo 'ProxyRequests off' >> conf/httpd.conf \
&& echo 'ProxyPass /ws ws://${SERVER_CONTAINER_NAME}:8080/ws interpolate' >> conf/httpd.conf

It might be cleaner to keep the modified versions of those config files outside of the image, and then copy them into the container during the build.
Alternatively, you could put all the shell commands in a script. During the build, COPY the script into the container. At the end of the script add something like this:
exec /usr/sbin/apache2ctl -f /etc/apache2/apache2.conf -DFOREGROUND
to start your server. Then have docker invoke the script as
CMD [ "/MyScript.sh" ]

Related

Docker httpd apache and getting cgi-bin to execute perl script

New to Docker and trying to get the cgi-bin working in a httpd image. My Dockerfile is as follows. The SED line adds the perl location to the first line of the example script that comes with the image:
FROM httpd:2.4.46
RUN sed -i '1c#!/usr/bin/perl' /usr/local/apache2/cgi-bin/printenv
I then build and run with:
docker build -t my-apache2 .
docker run -dit --name my-running-app -p 8080:80 my-apache2
I then navigate to localhost:8080/cgi-bin/printenv but instead of the script executing I get the code displayed as text. It appears the httpd image comes with ScriptAlias enabled by default. Any ideas please?
You also need to enable mod_cgid
FROM httpd:2.4.46
RUN sed -i '1c#!/usr/bin/perl' /usr/local/apache2/cgi-bin/printenv
RUN chmod +x /usr/local/apache2/cgi-bin/printenv
CMD httpd-foreground -c "LoadModule cgid_module modules/mod_cgid.so"

How to install mod_pagespeed in docker apache httpd

I have a docker based apache httpd server. I need to install mod_pagespeed into that.
The flavour I am using is debian based not alpine based for now - for some reasons.
Following is the list of commands required to install the module in debian/ubuntu dist - from the official site
wget https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb
sudo dpkg -i mod-pagespeed-*.deb
sudo apt-get -f install
This is giving error
dpkg: dependency problems prevent configuration of mod-pagespeed-stable:
mod-pagespeed-stable depends on apache2; however:
Package apache2 is not installed.
This is obvious because there is no apache2 service installed, only httpd command works.
Even the folder structure is different then regular debian/ubuntu installation.
I don't find any .so file anywhere, otherwise I can put it in some directory and do a LoadModule.
I guess I need to do a custom build from source, is there any easy way?
You may use the following Dockerfile as a base:
FROM debian:stretch
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_PID_FILE /var/run/apache2/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
ENV APACHE_LOG_DIR /var/log/apache2
ENV LANG C
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y apache2 wget \
&& wget https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb -O /tmp/modpagespeed.deb \
&& dpkg -i /tmp/modpagespeed.deb
RUN mkdir -p /var/log/apache2 /var/run/apache2 /var/lock/apache2 \
&& chown www-data:www-data /var/log/apache2 /var/run/apache2 /var/lock/apache2
CMD ["apache2", "-DFOREGROUND"]
EXPOSE 80
Build the image and launch a container, you'll get a response header similar to X-Mod-Pagespeed: 1.13.35.2-0.
Hope this helps!
Mostly #Michael's answer is correct, however for those who uses default docker's apache module (like me) following answer would suffice.
Because debian's apache installation is different than docker apache's installation. (And if you already have setup/customised all the configuration and cannot re-customise to be debian's structure)
I have built the pagespeed module from that answer and then copied the module to my installation.
Dockerfile
FROM debian:stretch as pagespeed
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_PID_FILE /var/run/apache2/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
ENV APACHE_LOG_DIR /var/log/apache2
ENV LANG C
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y apache2 wget \
&& wget https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb -O /tmp/modpagespeed.deb \
&& dpkg -i /tmp/modpagespeed.deb
FROM httpd:2.4.43
# all these things are my custom configuration. You probably don't need these
COPY --chown=root:www-data ./docker-assets/httpd-custom.conf $HTTPD_PREFIX/conf/httpd.conf
COPY --chown=root:www-data ./docker-assets/httpd-default.conf $HTTPD_PREFIX/conf/extra/httpd-default.conf
COPY --chown=root:www-data ./docker-assets/httpd-vhosts-custom.conf $HTTPD_PREFIX/conf/extra/httpd-vhosts.conf
COPY --chown=root:www-data ./docker-assets/httpd-ssl.conf $HTTPD_PREFIX/conf/extra/httpd-ssl.conf
COPY --chown=root:www-data ./docker-assets/httpd-mpm.conf $HTTPD_PREFIX/conf/extra/httpd-mpm.conf
# pagespeed module adding as custom build here. You may need to change some paths in .load file
COPY --chown=root:www-data ./docker-assets/pagespeed.load $HTTPD_PREFIX/conf/extra/
COPY --chown=root:www-data ./docker-assets/pagespeed.conf $HTTPD_PREFIX/conf/extra/
COPY --chown=root:www-data ./docker-assets/pagespeed_libraries.conf $HTTPD_PREFIX/conf/extra/
# Or directly copy from build stage
# COPY --from=pagespeed --chown=root:www-data /etc/apache2/mods-available/pagespeed.conf $HTTPD_PREFIX/conf/extra/
# COPY --from=pagespeed --chown=root:www-data /etc/apache2/conf-available/pagespeed_libraries.conf $HTTPD_PREFIX/conf/extra/
COPY --from=pagespeed --chown=root:www-data /usr/lib/apache2/modules/mod_pagespeed.so $HTTPD_PREFIX/modules/
COPY --from=pagespeed --chown=root:www-data /usr/lib/apache2/modules/mod_pagespeed_ap24.so $HTTPD_PREFIX/modules/
# pagespeed end

Docker Container from php:5.6-apache as root

This would be related to Docker php:5.6-Apache Development Environment missing permissions on volume mount
I have tried pretty much everything to make the mounted volume be readable by www-data, my current solution is trying to move by scripts the folders needed by the application to /var and giving the proper permissions to be writable by www-data but that is becoming hard to maintain.
Giving the fact that it's a development environment I don't mind being a security hole so I would like to run apache as root and I get
Error: Apache has not been designed to serve pages while running as
root. There are known race conditions that will allow any local user
to read any file on the system. If you still desire to serve pages as
root then add -DBIG_SECURITY_HOLE to the CFLAGS line in your
src/Configuration file and rebuild the server. It is strongly
suggested that you instead modify the User directive in your
httpd.conf file to list a non-root user.
Is there any easy way I can accomplish this using the docker image php:5.6-apache?
This is my docker-compose.yml
version: '2'
services:
api:
container_name: api
privileged: true
build:
context: .
dockerfile: apigility/Dockerfile
ports:
- "2020:80"
volumes:
- /ft/code/api:/var/www:rw
And this is my Dockerfile:
FROM php:5.6-apache
USER root
RUN apt-get update \
&& apt-get install -y sudo openjdk-7-jdk \
&& echo "www-data ALL=NOPASSWD: ALL" >> /etc/sudoers
RUN apt-get install -y git zlib1g-dev libmcrypt-dev nano vim --no-install-recommends \
&& apt-get clean \
&& rm -r /var/lib/apt/lists/* \
&& docker-php-ext-install mcrypt zip \
&& curl -sS https://getcomposer.org/installer \
| php -- --install-dir=/usr/local/bin --filename=composer \
&& a2enmod rewrite \
&& sed -i 's!/var/www/html!/var/www/public!g' /etc/apache2/apache2.conf \
&& echo "AllowEncodedSlashes On" >> /etc/apache2/apache2.conf \
&& cp /usr/src/php/php.ini-production /usr/local/etc/php/php.ini \
&& printf '[Date]\ndate.timezone=UTC' > /usr/local/etc/php/conf.d/timezone.ini
WORKDIR /var/www
Why not to do exactly what it says in the question you referred to?
RUN usermod -u 1000 www-data
RUN groupmod -g 1000 www-data
This is not a hack. It's a proper solution to the problem you have in the development environment.
So, I managed to make the mounted data available for www-data by using the part of the answer in the related post but another step is required for it to work.
After you run docker-machine start default you need to ssh into it and run the following:
sudo mkdir --parents /code [where /code is the shared folder in virtualbox]
sudo mount -t vboxsf -o uid=999,gid=999 code /code [this is to make sure the uid and gid is 999 for the next part to work]
Then in your Dockerfile add
RUN usermod -u 999 www-data \
&& groupmod -g 999 www-data
After it's mounted, /code will have the owner www-data, and problem solved!
Another and better solution.
Add this in your dockerfile
RUN cd ~ \
&& apt-get -y install dpkg-dev debhelper libaprutil1-dev libapr1-dev libpcre3-dev liblua5.1-0-dev autotools-dev \
&& apt-get source apache2.2-common \
&& cd apache2-2.4.10 \
&& export DEB_CFLAGS_SET="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -DBIG_SECURITY_HOLE" \
&& dpkg-buildpackage -b \
&& cd .. \
&& dpkg -i apache2-bin_2.4.10-10+deb8u7_amd64.deb \
&& dpkg -i apache2.2-common_2.4.10-10+deb8u7_amd64.deb
After that, you could be able to run apache as root.
PS : apache2-2.4.10, apache2-bin_2.4.10-10+deb8u7_amd64.deb and apache2.2-common_2.4.10-10+deb8u7_amd64.deb could change according to your source

Starting a service inside of a Dockerfile

I'm building a Docker container and in this container I am downloading the Apache service. Is it possible to automatically start the Apache service at some point? Systemctl start httpd does not work inside of the Dockerfile.
Basically, I want the apache service to be started when the docker container is started.
FROM centos:7
MAINTAINER me <me#me.com>
RUN yum update -y && yum install -y httpd php
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
EXPOSE 80
EXPOSE 443
CMD ["/usr/sbin/init"]
Try using CMD ["/usr/sbin/httpd", "-DFOREGROUND"].
You also can run :
docker run -d <image name> /usr/sbin/httpd -DFOREGROUND
According to the Docker reference (Entrypoint reference), in the scenario you describe, you would use ENTRYPOINT, as you want your web server to "immutably" start. CMD is for commands or command line options that you are likely change/be overwritten:
Command line arguments to docker run will be appended after all elements in an exec form ENTRYPOINT, and will override all elements specified using CMD. This allows arguments to be passed to the entry point, i.e., docker run -d will pass the -d argument to the entry point.
If you must override an ENTRYPOINT, e.g. for testing/diagnostics, use the specific --entrypoint option.
Further:
You can use the exec form of ENTRYPOINT to set fairly stable default commands and arguments and then use either form of CMD to set additional defaults that are more likely to be changed.
So, ENTRYPOINT for the fixed services/application part, CMD for overrideable commands or options.
Using both ENTRYPOINT and CMD allows you to set a "fixed" commands part (including options) and a "variable" part. Like so:
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
Which means, in your case you may consider to have:
ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["-DFOREGROUND"]
Which allows you do:
docker run -d <image name>
when you want to run your web server in the foreground, but
docker run -d <image name> -DBACKGROUND
if you want that same server to run with the -DBACKGROUND option overriding only the -DFOREGROUND part.

Cant get a Docker image with apache to display the test webpage

I have a docker image where I have put apache. I want it to that when the container starts, apache starts and I can visit the test page. However, the page is not appearing when I try.
This is my current dockerfile:
FROM centos:7
MAINTAINER me <me#me.com>
RUN yum update -y && yum install -y httpd php
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
EXPOSE 80
EXPOSE 443
CMD ["/usr/sbin/init"]
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
I am running the container with the command docker run -d -P <container_name>, and when I do docker ps, I see the ports section being populated correctly, with 0.0.0.0:32784->80/tcp, 0.0.0.0:32783->443/tcp as the output.
The url im trying to use to access it is 172.17.0.2:32784.
Any ideas?
Turns out the issue was that I was trying to connect with the docker containers IP, when the IP I shouldve been connecting with the IP of the server that it was hosted on.
Derp.