Running headless Chrome / Puppeteer with --no-sandbox

34,857

Solution 1

I was hitting a similar problem trying to run Chromium headless in an Alpine Docker container, and apparently so are many other (e.g., here, here). The --no-sandbox option is a straightforward workaround but obviously a poor security practice. What worked for me was setting a custom seccomp.

Download this file (if interested, see the author's notes here). Then pass the option --security-opt seccomp=path/to/chrome.json when starting Docker, or specify the same option in your docker-compose.yml if you're using one.

Solution 2

In your nodejs code when you launch your browser, you can pass the --no-sandbox argument.

example:-

const launchBrowser = async () => {
  puppetBrowser = await puppeteer.launch({
    args: ['--no-sandbox'],
    timeout: 10000,
  });
};

Solution 3

There is no need of a timeout,

const browser = await puppeteer.launch({headless: true, args:['--no-sandbox']});

Solution 4

Background

I was the OP. Months have went by and I continue to see people having similar problems all over the internet. Github issues and SO. Due to that I want to show everyone how I solved this issue.

Problem

Running Puppeteer on Debian fails due to missing libs.

Solution

I was able to run the application using a Docker file and adding a config option to Puppeteer.

Examples

Docker File

FROM node:8
ENV HOST 0.0.0.0
EXPOSE 8080
RUN apt-get update

# for https
RUN apt-get install -yyq ca-certificates
# install libraries
RUN apt-get install -yyq libappindicator1 libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6
# tools
RUN apt-get install -yyq gconf-service lsb-release wget xdg-utils
# and fonts
RUN apt-get install -yyq fonts-liberation

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN mkdir -p /usr/src/app/views

# install the necessary packages
RUN npm install

CMD npm run start

Puppeteer

const browser = await puppeteer.launch({
          args: ['--no-sandbox', '--disable-setuid-sandbox'],
          ignoreHTTPSErrors: true,
          dumpio: false
        });

I hope this helps. Basically when running the app you will install the missing libs by configuring your Docker file then when your app is running the config options passed to the Puppeteer object will allow your app to run on Debian.

Share:
34,857
wuno
Author by

wuno

Director of Software Engineer (CEH)

Updated on December 30, 2020

Comments

  • wuno
    wuno over 3 years

    Background

    I built an application that uses Puppeteer on my localhost. Now that I am trying to deploy it into a debian environment the script that runs Puppeteer is timing out. After researching it I realized it is a common problem. Most debian environments are missing the dependencies needed to run Chromium.

    Problem

    I found some recommended ways to run the application using Docker here.

    I can run the application using Docker, but once I add the Chrome specific data to my Docker file I am getting a few errors.

    Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted

    It is suggested to run the app as a user made in the Docker file. But, when I add that user, the user gets the error mentioned above.

    Then when I try and run the application as root, I get a new error,

    Running as root without --no-sandbox is not supported.

    Although it is not recommended, I want to get the app running even with --no-sandbox to see if it works.

    Example

    I have been running the application like this,

    docker run -p 3000:3000 user/app-name
    

    Docker File

    FROM ubuntu:16.04
    
    # Application parameters and variables
    ENV NODE_ENV=production
    ENV PORT=3000
    ENV Root_Dir /
    ENV application_directory /usr/src/app
    ENV font_directory /usr/share/fonts/noto
    
    # Configuration for Chrome
    ENV CONNECTION_TIMEOUT=60000
    ENV CHROME_PATH=/usr/bin/google-chrome
    
    RUN mkdir -p $application_directory
    RUN mkdir -p $font_directory
    
    # Dependencies needed for packages downstream
    RUN apt-get update && apt-get install -y \
      apt-utils \
      unzip \
      fontconfig \
      locales \
      gconf-service \
      libasound2 \
      libatk1.0-0 \
      libc6 \
      libcairo2 \
      libcups2 \
      libdbus-1-3 \
      libexpat1 \
      libfontconfig1 \
      libgcc1 \
      libgconf-2-4 \
      libgdk-pixbuf2.0-0 \
      libglib2.0-0 \
      libgtk-3-0 \
      libnspr4 \
      libpango-1.0-0 \
      libpangocairo-1.0-0 \
      libstdc++6 \
      libx11-6 \
      libx11-xcb1 \
      libxcb1 \
      libxcomposite1 \
      libxcursor1 \
      libxdamage1 \
      libxext6 \
      libxfixes3 \
      libxi6 \
      libxrandr2 \
      libxrender1 \
      libxss1 \
      libxtst6 \
      ca-certificates \
      fonts-liberation \
      libappindicator1 \
      libnss3 \
      lsb-release \
      xdg-utils \
      wget
    
    # It's a good idea to use dumb-init to help prevent zombie chrome processes.
    ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 /usr/local/bin/dumb-init
    RUN chmod +x /usr/local/bin/dumb-init
    
    # Install Node.js
    RUN apt-get install --yes curl &&\
      curl --silent --location https://deb.nodesource.com/setup_8.x | bash - &&\
      apt-get install --yes nodejs &&\
      apt-get install --yes build-essential
    
    # Install emoji's
    RUN cd $font_directory &&\
      wget https://github.com/emojione/emojione-assets/releases/download/3.1.2/emojione-android.ttf &&\
      wget https://github.com/googlei18n/noto-cjk/blob/master/NotoSansCJKsc-Medium.otf?raw=true && \
      fc-cache -f -v
    
    RUN apt-get update && apt-get install -y wget --no-install-recommends \
        && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
        && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
        && apt-get update \
        && apt-get install -y google-chrome-unstable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst ttf-freefont \
            --no-install-recommends \
        && rm -rf /var/lib/apt/lists/* \
        && apt-get purge --auto-remove -y curl \
        && rm -rf /src/*.deb
    
    # Cleanup
    RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
    
    # Install puppeteer so it's available in the container.
    RUN npm i puppeteer
    
    # Add user so we don't need --no-sandbox.
    RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
       && mkdir -p /home/pptruser/Downloads \
       && chown -R pptruser:pptruser /home/pptruser \
       && chown -R pptruser:pptruser /node_modules
    
    RUN cd $application_directory
    
    WORKDIR $application_directory
    
    # Install app dependencies
    COPY package.json .
    
    # Bundle app source
    COPY . .
    
    # Build
    RUN npm install
    
    USER pptruser
    
    # Expose the web-socket and HTTP ports
    EXPOSE 3000
    ENTRYPOINT ["dumb-init", "--"]
    CMD ["google-chrome-unstable", "npm", "start"]
    

    Question

    How do I run Docker and pass the ,

    --no-sandbox
    

    param so it will let me run this in root?

    Or, what do I need to change in my current Docker file so it will let me run it as the USER pptruser

    Current Problems -

    Runnning as

    USER pptruser
    

    Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted

    Running as

    root
    

    Running as root without --no-sandbox is not supported.

  • Isaiah Norton
    Isaiah Norton over 5 years
    This is a giant security hole.
  • Cyril N.
    Cyril N. over 5 years
    @IsaiahNorton Could you tell me (us) if that's also the case in a Docker container, run as a non-root user?
  • Civilian
    Civilian almost 5 years
    A malicious site could potentially take over the docker container. It's not the end of the world, but the attacker would have access to any code and data inside the docker container.
  • Tobias Mühl
    Tobias Mühl about 4 years
    Anyone figured out the specific config option for docker-compose?
  • usethe4ce
    usethe4ce about 4 years
    For docker-compose, see the example here. Just note that the relative path is relative not to the yaml, but to your working directory.
  • Pragyanshu Sharma
    Pragyanshu Sharma almost 4 years
    Well i wasn't using puppeteer library directly,this made my task difficult to implement this but somehow your answer helped me figure out the problem with the library node-html-to-image and i fixed it.
  • GeorGios
    GeorGios over 3 years
    @IsaiahNorton Why is it a security hole? What is you alternative solution? Do you have a better idea or a different parameter to increase security?
  • c4k
    c4k over 2 years
    This solution is now 6 years old. Has anyone found a "better" alternative ?