skip to Main Content

I have a Docker image that runs Apache, and I have configured Apache (through httpd.conf) to listen on port 8080.

Listen 8080

When I build my image and run it, I’m able to successfully connect to my website via port 8080, so all seems well at this point.

docker build -t my/apache:8080 .
docker run --name "MyWebsite" -p 8080:8080 -v ~/dir:/mnt/dir -d -t my/apache:8080

However, when I list my running containers using docker ps, I see that port 80 has also been exposed for some reason.

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                            NAMES
23c4e1f0ea66        my/apache:8080      "/docker-entrypoint.…"   12 minutes ago      Up 12 minutes       80/tcp, 0.0.0.0:8080->8080/tcp   MyWebsite

When I shell on to the running container and search for instances of “Listen 80”, nothing shows up other than the instance of “Listen 8080” that I added to httpd.conf.

docker exec -it 23c4e1f0ea66 /bin/bash
grep -ri "Listen 80"

My Dockerfile contains only one EXPOSE declaration – EXPOSE 8080. However, I don’t believe this actually exposes the port anyway, and is intended more as a way of documenting which port should be exposed when running a container that utilizes the image.

How can I find out when is exposing port 80, and crucially, how can I stop it from being exposed?

Dockerfile

FROM httpd:2.4

COPY httpd.conf /usr/local/apache2/conf/
COPY docker-entrypoint.sh /

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["apache"]

### Apache (proxies to MapProxy).
EXPOSE 8080

Entrypoint script

#!/bin/bash
set -e

if [ "$1" = 'apache' ]; then
        echo "Starting Apache"
        httpd-foreground
fi

exec "$@"

HTTP config

ServerRoot "/usr/local/apache2"

Listen 8080

LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
<IfModule !mpm_prefork_module>
</IfModule>
<IfModule mpm_prefork_module>
</IfModule>
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so

<IfModule unixd_module>
        User daemon
        Group daemon
</IfModule>

ServerAdmin [email protected]
ServerName mapproxy.gcs.lmkcloud.net:8080
DocumentRoot "/usr/local/apache2/htdocs"
ErrorLog /proc/self/fd/2

LogLevel warn

<IfModule log_config_module>
        LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined
        LogFormat "%h %l %u %t "%r" %>s %b" common

        <IfModule logio_module>
                LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i" %I %O" combinedio
        </IfModule>

        CustomLog /proc/self/fd/1 common

</IfModule>

<IfModule mime_module>
        TypesConfig conf/mime.types
        AddType application/x-compress .Z
        AddType application/x-gzip .gz .tgz
</IfModule>

<IfModule ssl_module>
        SSLRandomSeed startup builtin
        SSLRandomSeed connect builtin
</IfModule>

ProxyPreserveHost On
ProxyPass / http://example.com:8001/ retry=1 acquire=3000 timeout=20 Keepalive=On
ProxyPassReverse / http://example.com:8001/

2

Answers


  1. Port 80 is exposed by the parent Dockerfile for httpd:2.4 image –
    https://github.com/docker-library/httpd/blob/75e85910d1d9954ea0709960c61517376fc9b254/2.4/Dockerfile

    A EXPOSE statement inside Dockerfile is going to give you an output eventually in docker ps. However, that’s exposed only to the container network & will not allow communication via the defined ports to containers outside of the same network or to the host machine. To allow this to happen you need to publish the ports.


    Example –

    docker run -dit --expose 8008 httpd:2.4

    Output –

    CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                  PORTS                              NAMES
    d628b537aded        httpd:2.4                 "httpd-foreground"       3 seconds ago       Up 2 seconds            80/tcp, 8008/tcp                   objective_dewdney
    

    This exposes the container port. Argument --expose is equal to a statement using EXPOSEin Dockerfile.


    Let’s try to publish the port now –

    docker run -dit -p 8009 httpd:2.4

    Output –

    CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                  PORTS                              NAMES
    2c8c93a78e97        httpd:2.4                 "httpd-foreground"       2 seconds ago       Up 2 seconds            80/tcp, 0.0.0.0:32768->8009/tcp    keen_swirles
    

    See the 0.0.0.0:32768, it’s now published to the host machine with a random ephemeral port i.e 32768. You can publish it on a specific host port as well.


    Example –

    docker run -dit -p 8009:8009 httpd:2.4

    Output –

    CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                  PORTS                              NAMES
    1023df9822e5        httpd:2.4                 "httpd-foreground"       2 seconds ago       Up 2 seconds            80/tcp, 0.0.0.0:8009->8009/tcp     fervent_almeida
    

    In a nutshell, there is no way right now to unexpose the port 80 from parent Dockerfile. You can certainly expose more ports.

    It’s an open issue –
    https://github.com/moby/moby/issues/2210
    https://github.com/moby/moby/issues/3465

    Adding @BMitch comment to the answer which I believe is spot on since containers can communicate with each other in the same network irrespective of port exposed –

    As per @BMitch –

    EXPOSE is only documentation/metadata. It doesn’t change how
    containers communicate with each other. docker ps is just letting you
    know a port the image creator documented could be published but hasn’t
    been (since there’s no host side of the map). There’s nothing to
    change here unless you have code or users that insist this
    documentation matches your environment. For that, you’d have to
    rebuild the upstream image.

    Login or Signup to reply.
  2. There is a hint on how to do this at the DockerHub page. An alternative config file must be obtained and added to the container via the Dockerfile.

    First get a copy of the config file:

    docker run --rm httpd:2.4 cat /usr/local/apache2/conf/httpd.conf > my-httpd.conf
    

    Then edit the my-httpd.conf file and modify the port:

    Listen 8080
    

    Finally add to the Dockerfile the instruction to copy it:

    COPY ./my-httpd.conf /usr/local/apache2/conf/httpd.conf
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search