How does one use Apache in a Docker Container and write nothing to disk (all logs to STDIO / STDERR)? - apache

I'm running Apache2 in a docker container and want to write nothing to the disk, writing logs to stdout and stderr. I've seen a few different ways to do this (Supervisord and stdout/stderr, Apache access log to stdout) but these seem like hacks. Is there no way to do this by default?
To be clear, I do not want to tail the log, since that will result in things being written to the disk in the container.
The "official" version checked into Docker Hub (https://hub.docker.com/_/httpd/) still write to disk.
Also, what do I need to do to stop Apache from failing when it tries to roll the logs?
One other thing - ideally, I'd really like to do this without another add-on. nginx can do this trivially.

I'm not positive that this won't mess with httpd's logging at all (e.g. if it tries to seek within the file), but you can set up symlinks from the log paths to /dev/stdout and /dev/stderr, like so:
ln -sf /dev/stdout /path/to/access.log
ln -sf /dev/stderr /path/to/error.log
The entry command to the vanilla httpd container from Docker Hub could be made to be something like
ln -sf /dev/stdout /path/to/access.log && ln -sf /dev/stderr /path/to/error.log && /path/to/httpd

According to the apache mailing list, you can just directly write to /dev/stdio (on Unix like systems) as that's just a regular ol' file handle. Easy! Pasting...
The most efficient answer depends on your operating system. If you're
on a UNIX like system which provides /dev/stdout and /dev/stderr (or
perhaps /dev/fd/1 and /dev/fd/2) then use those file names. If that
isn't an option use the piped output feature. For example, from my
config:
CustomLog "|/usr/sbin/rotatelogs -c -f -l -L
/private/var/log/apache2/test-access.log
/private/var/log/apache2/test-access.log.%Y-%m-%d 86400 "
krader_custom ErrorLog "|/usr/sbin/rotatelogs -c -f -l -L
/private/var/log/apache2/test-error.log
/private/var/log/apache2/test-error.log.%Y-%m-%d 86400"
Obviously you'll want to substitute another program for
/usr/sbin/rotatelogs in the example above that writes the data where
you want it to go.
https://mail-archives.apache.org/mod_mbox/httpd-users/201508.mbox/%3CCABx2=D-wdd8FYLkHMqiNOKmOaNYb-tAOB-AsSEf2p=ctd6sMdg#mail.gmail.com%3E

I know it's an old question, but I had this need today.
On an Alpine 3.6, the following instructions, in httpd.conf, are working:
Errorlog /dev/stderr
Transferlog /dev/stdout
I add them to my container this way:
FROM alpine:3.6
RUN apk --update add apache2
RUN sed -i -r 's#Errorlog .*#Errorlog /dev/stderr#i' /etc/apache2/httpd.conf
RUN echo "Transferlog /dev/stdout" >> /etc/apache2/httpd.conf
...

I adjusted config, as from the Dockerfile recipe of httpd, they use sed to adjust the config, to change ErrorLog and CustomLog as follows:
sed -ri ' \
s!^(\s*CustomLog)\s+\S+!\1 /proc/self/fd/1!g; \
s!^(\s*ErrorLog)\s+\S+!\1 /proc/self/fd/2!g; \
' /usr/local/apache2/conf/httpd.conf \
See https://github.com/docker-library/httpd/blob/master/2.4/Dockerfile (towards the end of the file)

You can send your ErrorLog to syslog directly, and you can send any CustomLog (access log) to any executable that reads from stdin. There are log aggregation tools, or you can again use syslog w/ e.g. /usr/bin/logger.

You could try using the dockerize tool. With that you could wrap the httpd-foreground command and redirect its log files to stdout/stderr (don't know exactly the httpd log file paths, simply adjust them to your needs):
CMD ["dockerize", "-stdout", "/var/log/httpd.log", "-stderr", "/var/log/httpd.err", "httpd-foreground"]
In addition to that you could grab that containers stdout/stderr then by specifying a syslog log driver and redirect them to the /var/log/syslog log file on the docker host:
docker run -d --log-driver=syslog ...

Related

Find httpd.conf file location after it's been changed by -f flag

Httpd processes use a non-default configuration file if they are run with the -f flag.
For example
/home/myuser/apache/httpd-2.4.8/bin/httpd -f /confFiles/apache/2.4.8/apache.conf -k start
will use this configuration file: /confFiles/apache/2.4.8/apache.conf
I need to get this location and would rather not have to check for possible -f flags used to start httpd.
The answer here says to run /path/to/httpd -V and concatenate
-D SERVER_CONFIG_FILE="conf/httpd.conf"
with
-D HTTPD_ROOT="/etc/httpd"
to get the final path to the config file.
However, this path will not be the correct one if the -f flag is used to start the httpd process.
Is there a command that can get the config file that is actually being used by the process?
The answer you refer to mentions the paths httpd was compiled with, but as you say those can be manually changed with parameters.
The simple way to check is the command line, if process is called "httpd" (standard name), a simple ps will reveal the config file being used:
ps auxw | grep httpd
Or querying the server if server has mod_info loaded, in command line or with your favourite browser:
curl "http://yourserver.example.com/server-info?server" | grep -i "config file"
Note: mod_info should not be publicaly available for everyone to see.

How to add EnvironmentFile directive to systemctl using Docker with centos7/httpd base image

I am not sure if this is possible without creating my own base image, but I use environment variables in /etc/environment on our servers and typically make them accessible to apache by doing the following:
$ printf "HTTP_VAR1=var1-value\n\
HTTP_VAR2=var2-value"\
>> /etc/environment
$ mkdir /usr/lib/systemd/system/httpd.service.d
$ printf "[Service]\n\
EnvironmentFile=/etc/environment"\
> /usr/lib/systemd/system/httpd.service.d/environment.conf
$ systemctl daemon-reload
$ systemctl restart httpd
$ reboot
The variables are then available in any PHP calls to getenv('HTTP_VAR1'); and etc. However, in running this from a docker file I get dbus errors on the systemctl commands. Without the systemctl commands it seems the variables are not available to apache as it seems the new EnvironmentFile directive doesn't take effect. My docker file snippet:
FROM centos/httpd:latest
RUN printf "HTTP_VAR1=var1-value\n\
HTTP_VAR2=var2-value"\
>> /etc/environment
RUN mkdir /usr/lib/systemd/system/httpd.service.d &&\
printf "[Service]\n\
EnvironmentFile=/etc/environment"\
> /usr/lib/systemd/system/httpd.service.d/environment.conf
RUN systemctl daemon-reload &&\
systemctl restart httpd
COPY entrypoint.sh /entrypoint.sh
So I happened upon the answer to the issue today. It seems that systemd drops backslashes inside single quotes, but it may effect double-quotes too from what I saw in testing. I found the systemd development mailing list thread from April 2014 where patching the issue was being discussed. It seems as though the fix never made it in. So we have to work around it.
In attempting to work around it I noticed some issues with actually reading the variables at all. It seemed as though either Apache or php-cli would get the correct variables, and sometimes not at all, it took a bit of sleuthing to figure out what was going on. Then I started reading into the systemd's EnvironmentFile directive to see if there was more to gain from the docs. It turns out it does not evaluate bash so export won't work. It expects a text file with variable assignments and herein lies one of the main issues that might keep this from being resolved.
I then devised a workable solution. Utilizing systemd's ExecStartPre directive I am able to run a script on startup of the httpd service. I then read in the environment file and write a new plain text one that will then be used by httpd's systemd unit. Here is the code:
Firstly, I moved my variables to /etc/profile.d/ directory rather than /etc/environment file.
file: /etc/profile.d/environment.sh
This is where we store all our environment variables, this gets easily sourced on all interactive shell logins. In the rarer cases where we need to have these variables available non-interactively we can either provide --login flag to /bin/bash or source it manually.
export HTTP_VAR1=var1-value-with-a-back\slash
export HTTP_VAR2=var2-value
file: /usr/lib/systemd/system/httpd.service.d/environment.conf
Our drop-in unit file to extend how the httpd service works. I add in a script that runs before httpd starts up. This gets ran on all httpd restarts and starts. The script that runs generates a plain text file at /etc/profile.d/environment.env which we subsequently tell systemd to load as an EnvironmentFile.
[Service]
ExecStartPre=/usr/bin/bash -c "/usr/local/bin/generate-plain-environment-file"
EnvironmentFile=/etc/profile.d/environment.env
file: /usr/local/bin/generate-plain-environment-file
Here is the script I am using, I whipped this together really fast, I really don't think it is that robust and it could be better. It just removes the export from the beginning of the lines and then escapes any backslashes since systemd drops single backslashes. A more proper solution might be to use bash to evaluate each line and obtain the variable value in case of usage of variables or other bash in the actual bash variables, then output them as plain text name=value assignments, however this is not part of my use-case so I didn't bother.
#!/bin/bash
cd /etc/profile.d/
rm -rf "./environment.env"
while IFS='' read -r line || [[ -n "$line" ]]; do
echo $(echo "${line}" | sed 's/^export //' | sed 's/\\/\\\\/g') >> "./environment.env";
done < "./environment.sh"
file: /etc/profile.d/environment.env
This is the resulting file generated by the described script.
HTTP_VAR1=var1-value-with-a-back\\slash
HTTP_VAR2=var2-value
Conclusion is that the I now have two files with the same thing in them but I only need to maintain the one, the other is generated each time we restart httpd. Also, we fix the backslash issue in the process. Hurray!

Graceful restart of Apache on Lion Server

I recently upgraded my Mac's OS from Lion to Lion Server, which changes how the httpd.conf settings are read when Apache is started. In particular, environment variables like WEBSHARING_ON and MACOSXSERVER are set by the Server.app process, so that extra modules and files are read in when Apache is started.
So now, to restart the Apache server with all the proper settings and modules loaded, I have to use the command:-
sudo serveradmin stop web && sudo serveradmin start web
Previously, I would run:-
sudo apachectl -S
sudo apachectl graceful
I prefer the latter method by far. For one thing, the command returns much quicker, and I also imagine that the apache / httpd server process doesn't completely terminate, just the settings are reloaded.
So, is there a way to gracefully restart Apache in Lion Server?
The quick answer is no.
The 'apachectl' program is actually just a shell script, so (after realising this) it's easy to see what it's doing, and why it's not doing what I expected.
When restarting Apache (gracefully or otherwise) on a Mac, the relevant launchctl job is just unloaded and reloaded, which I imagine is not as per the official Apache description of a graceful restart:
The USR1 or graceful signal causes the parent process to advise the children to exit after their current request (or to exit immediately if they're not serving anything)
The reason apachectl -S doesn't show the configured virtual servers is because this command is not run by launchctl, and so the environment variables set in /System/Library/LaunchDaemons/org.apache.httpd.plist are not loaded.
So, apachectl graceful, apachectl restart and others do load the proper variables, and therefore read the config files properly, but not all commands do by default.
To overcome this, I've manually edited /usr/sbin/apachectl, as below. All I did was add "-D MACOSXSERVER -D WEBSERVICE_ON" where appropriate.
case $ARGV in
start)
run_launchctl load -w $LAUNCHD_JOB
ERROR=$?
;;
stop|graceful-stop)
run_launchctl unload -w $LAUNCHD_JOB
ERROR=$?
;;
restart|graceful)
run_launchctl unload -w $LAUNCHD_JOB 2> /dev/null
run_launchctl load -w $LAUNCHD_JOB
ERROR=$?
;;
startssl|sslstart|start-SSL)
echo The startssl option is no longer supported.
echo Please edit httpd.conf to include the SSL configuration settings
echo and then use "apachectl start".
ERROR=2
;;
configtest)
$HTTPD -t -D MACOSXSERVER -D WEBSERVICE_ON
ERROR=$?
;;
status|fullstatus)
echo Go to $STATUSURL in the web browser of your choice.
echo Note that mod_status must be enabled for this to work.
;;
*)
$HTTPD $ARGV -D MACOSXSERVER -D WEBSERVICE_ON
ERROR=$?
esac

relocate apache's configuration files

is there a chance to use different location for apache's config files (on Windows)? Other than having to compile it myself and setting the proper #define HTTPD_ROOT value.
Thx rezna
This can be done by specifying the -f option when installing apache as a service on Windows.
The -f option accepts the location of the configuration file. For example, if your command to install the service was
httpd.exe -k install -n "MyServiceName"
Add -f "c:\files\my.conf", with your configuration file instead, like so:
httpd.exe -k install -n "MyServiceName" -f "c:\files\my.conf"
See the Apache manual for more information.

finding apache build options

I need to rebuild an apache server, but the original source is no longer available. Is there any way ( command line switch to httpd? ) to get the build options which were originally used?
Try -V which "Print the version and build parameters of httpd, and then exit."
httpd -V
Also, you can see the options for httpd via:
httpd -h
I found previous configure options in the build directory of apache root.
I'm a Centos 5/6 user.
Apache ver. is 2.2.27.
apachedir/build/config.nice
#! /bin/sh
#
# Created by configure
"./configure" \
"--prefix=/usr/local/apache2" \
"--enable-so" \
"--enable-mods-shared=most" \
"--enable-ssl" \
"--with-mpm=worker" \
"--enable-cgi" \
"$#"
I re-compiled apache 2.4.3 recently and change the MPM from worker to prefork, what you have to do if you still keep your original compiled directory without ran "make distclean" (if you ran "make clean" it still OK). You can use the SAME configure option to re-configure by exec ./config.status or you can find and copy './configure' from ./config.status (yes, all the original options that you used to run configure still there).
Here is part of my config.status...
if $ac_cs_silent; then
exec 6>/dev/null
ac_configure_extra_args="$ac_configure_extra_args --silent"
fi
if $ac_cs_recheck; then
set X /bin/sh **'./configure' '--enable-file-cache' '--enable-cache' '--enable-disk-cache' '--enable-mem-cache' '--enable-deflate' '--enable-expires' '--enable-headers' '--enable-usertrack' '--enable-cgi' '--enable-vhost-alias' '--enable-rewrite' '--enable-so' '--with-apr=/usr/local/apache/' '--with-apr-util=/usr/local/apache/' '--prefix=/usr/local/apache' '--with-mpm=worker' '--with-mysql=/var/lib/mysql' '--with-mysql-sock=/var/run/mysqld/mysqld.sock' '--enable-mods-shared=most' '--enable-ssl' 'CFLAGS=-Wall -O3 -ffast-math -frename-registers -mtune=corei7-avx' '--enable-modules=all' '--enable-proxy' '--enable-proxy-fcgi'** $ac_configure_extra_args --no-create --no-recursion
shift
$as_echo "running CONFIG_SHELL=/bin/sh $*" >&6
CONFIG_SHELL='/bin/sh'
export CONFIG_SHELL
exec "$#"
fi