dockerfirefoxx11

How can I run fIrefox from within a docker container


I'm trying to create a docker container that will let me run firefox, so I can eventually use a jupyter notebook. Right now, although I have successfully installed firefox, I cannot get a window to open.

Following instructions from running-gui-apps-within-docker, I created an image (i.e. "sample") with Firefox and then tried to run it using

$ docker run -it --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --net=host sample

When I did so, I got the following error:

root@machine:~# firefox
No protocol specified
Unable to init server: Could not connect: Connection refused
Error: cannot open display: :1

Using man docker run to understand the flags, I was not able to find the --net flag, though I did see a --network flag. However, replacing --net with --network didn't change anything. How do I specify a protocol, that will let me create an image from whose containers I will be able to run firefox?

PS - For what it's worth, when I check the value of DISPLAY, I get the predictable:

~# echo $DISPLAY
:1

Solution

  • I have been running firefox inside docker for quite some time so this is possible. With regards to the security aspects I think the following is the relevant parts:

    Building

    The build needs to match up uid/gid values with the user that is running the container. I do this with UID and GID build args:

    Dockerfile

    ...
    FROM fedora:35 as runtime
    
    ENV DISPLAY=:0
    
    # uid and gid in container needs to match host owner of
    # /tmp/.docker.xauth, so they must be passed as build arguments.
    ARG UID
    ARG GID
    
    RUN \
           groupadd -g ${GID} firefox && \
           useradd --create-home --uid ${UID} --gid ${GID} --comment="Firefox User" firefox && \
           true
    ...
    
    ENTRYPOINT [ "/entrypoint.sh" ]
    

    Makefile

    build:
            docker pull $$(awk '/^FROM/{print $$2}' Dockerfile | sort -u)
            docker build \
                    -t $(USER)/firefox:latest \
                    -t $(USER)/firefox:`date +%Y-%m-%d_%H-%M` \
                    --build-arg UID=`id -u` \
                    --build-arg GID=`id -g` \
                    .
    
    

    entrypoint.sh

    #!/bin/sh
    
    # Assumes you have run
    #      pactl load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1
    # on the host system.
    PULSE_SERVER=tcp:127.0.0.1:4713
    export PULSE_SERVER
    
    if [ "$1" = /bin/bash ]
    then
            exec "$@"
    fi
    
    exec /usr/local/bin/su-exec firefox:firefox \
            /usr/bin/xterm \
                    -geometry 160x15 \
                    /usr/bin/firefox --no-remote "$@"
    
    

    So I am running firefox as a dedicated non-root user, and I wrap it via xterm so that the container does not die if firefox accidentally exit or if you want to restart. It is a bit annoying having all these extra xterm windows, but I have not found any other way in preventing accidental loss of the .mozilla directory content (mapping out to a volume would prevent running multiple independent docker instances which I definitely want, and also from a privacy point of view not dragging along a long history is something I want. Whenever I do want to save something I make a copy of the .mozilla directory and save it on the host computer (and restore later in a new container)).

    Running

    run.sh

    #!/bin/bash
    
    export XSOCK=/tmp/.X11-unix
    export XAUTH=/tmp/.docker.xauth
    
    touch ${XAUTH}
    xauth nlist ${DISPLAY} | sed -e 's/^..../ffff/' | uniq | xauth -f ${XAUTH} nmerge -
    
    DISPLAY2=$(echo $DISPLAY | sed s/localhost//)
    if [ $DISPLAY2 != $DISPLAY ]
    then
            export DISPLAY=$DISPLAY2
            xauth nlist ${DISPLAY} | sed -e 's/^..../ffff/' | uniq | xauth -f ${XAUTH} nmerge -
    fi
    
    ARGS=$(echo $@ | sed 's/[^a-zA-Z0-9_.-]//g')
    
    docker run -ti --rm \
            --user root \
            --name firefox-"$ARGS" \
            --network=host \
            --memory "16g" --shm-size "1g" \
            --mount "type=bind,target=/home/firefox/Downloads,src=$HOME/firefox_downloads" \
            -v ${XSOCK}:${XSOCK} \
            -v ${XAUTH}:${XAUTH} \
            -e XAUTHORITY=${XAUTH} \
            -e DISPLAY=${DISPLAY} \
            ${USER}/firefox "$@"
    
    

    With this you can for instance run ./run.sh https://stackoverflow.com/ and get a container named firefox-httpsstackoverflow.com. If you then want to log into your bank completely isolated from all other firefox instances (protected by operating system process boundaries, not just some internal browser separation) you run ./run.sh https://yourbank.example.com/.