skip to Main Content

I try to run httpd:2.4-alpine docker image not as a root user.

Default behavior :

> docker run -p 80:80 -d --rm --name httpd httpd:2.4-alpine
3c271ae8abfc3f54c0e63d62a2ce26fcbeeef29064da66f4b3f6bd00480ad4fb
> docker exec httpd --name httpd whoami
root

After looking inside the Dockerfile definition of this image, one can see a www-data is created with an id 82 :

...
RUN set -x 
    && adduser -u 82 -D -S -G www-data www-data
# 82 is the standard uid/gid for "www-data" in Alpine
...

Let’s try to run this image using this user then :

> docker stop httpd # cleaning previous instance
> docker run -p 80:80 --rm --name httpd -u www-data httpd:2.4-alpine

This failed with this error :

AH00558: httpd: Could not reliably determine the server’s fully
qualified domain name, using 172.17.0.3. Set the ‘ServerName’
directive globally to suppress this message AH00558: httpd: Could not
reliably determine the server’s fully qualified domain name, using
172.17.0.3. Set the ‘ServerName’ directive globally to suppress this message [Tue Aug 30 15:57:25.958695 2022] [core:error] [pid 1:tid
140459379268424] (13)Permission denied: AH00099: could not create
/usr/local/apache2/logs/httpd.pid.XXXXXX [Tue Aug 30 15:57:25.959029
2022] [core:error] [pid 1:tid 140459379268424] AH00100: httpd: could
not log pid to file /usr/local/apache2/logs/httpd.pid

I’ve found this answer that seems to fix the problem, but because I’m in a docker context I don’t know how/if I can apply this solution.

Does someone out there know how I could run this image NOT as a root ?

2

Answers


  1. The reason for this is that by default the user www-data lacks the capability to bind a privileged port, in fact, any other regular will have the same issue.

    As you can see, only the parent process runs as the root user, and child processes run as the www-data user.

    /usr/local/apache2 # ps aux
    PID   USER     TIME  COMMAND
        1 root      0:00 httpd -DFOREGROUND
        8 www-data  0:00 httpd -DFOREGROUND
        9 www-data  0:00 httpd -DFOREGROUND
       10 www-data  0:00 httpd -DFOREGROUND
       92 root      0:00 sh
       98 root      0:00 ps aux
    

    By setting setcap 'cap_net_bind_service=+ep' to the httpd binary, you’ll be able to run it as the www-data user.

    In order to fix this, you need to create a new image, this is a Dockerfile example:

    FROM httpd:2.4-alpine
    
    RUN apk add libcap && chown -hR www-data:www-data /usr/local/apache2/ && 
      setcap 'cap_net_bind_service=+ep' /usr/local/apache2/bin/httpd
    
    USER www-data
    

    Once you have created the new image, you’ll be able to run the image as non-root.

    Logs:

    AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
    AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
    [Tue Aug 30 16:51:43.660323 2022] [mpm_event:notice] [pid 1:tid 281473523657800] AH00489: Apache/2.4.54 (Unix) configured -- resuming normal operations
    [Tue Aug 30 16:51:43.660358 2022] [core:notice] [pid 1:tid 281473523657800] AH00094: Command line: 'httpd -D FOREGROUND'
    

    Running as:

    /usr/local/apache2 $ whoami
    www-data
    
    Login or Signup to reply.
  2. While @javierlga’s answer is correct, you don’t need to build a new image to remediate this issue. There are three things we need to do:

    1. Run Apache as the www-data user
    2. Grant the www-data user the ability to bind to privileged ports, and
    3. Deal with the need to write a pid file into /usr/local/apache2/logs.

    We can accomplish (1) using the -u argument to docker run:

    docker run -u www-data ...
    

    We can solve (2) using with the --cap-add argument to docker run:

    docker run -u www-data --cap-add net_bind_service ...
    

    That leaves us with (3). We can see the problem in the logs you posted in your question:

    Permission denied: AH00099: could not create /usr/local/apache2/logs/httpd.pid.XXXXXX
    

    Apache is trying to write a file into /usr/local/apache2/logs, but
    the www-data user does not have permission to create files in this
    directory.

    There are a number of ways of solving this problem. The simplest is probably moving the pidfile to /tmp, which we can do by passing the necessary configuration directive to httpd using the -C command line option:

    docker run ... docker.io/httpd:2.4.54-alpine 
      httpd-foreground -C 'PidFile /tmp/httpd.pid'
    

    Putting it all together, we get:

    docker run -u www-data 
      --cap-add net_bind_service -p 8080:80 
      docker.io/httpd:2.4.54-alpine 
      httpd-foreground -C 'PidFile /tmp/httpd.pid'
    

    Or in a docker-compose.yaml file:

    version: "3"
    
    services:
      httpd:
        image: docker.io/httpd:2.4.54-alpine
        command: [httpd-foreground, -C, "PidFile /tmp/httpd.pid"]
        user: www-data
        ports:
          - "8080:80"
        cap_add:
          - net_bind_service
    

    That runs without errors and does not require maintaining our own image.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search