I'm attempting to figure out how to open a headed browser to do some tasks from inside of NestJs application running in a docker container.
Application Code:
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { chromium } from "playwright";
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
async getHello(): Promise<string> {
const browser = await chromium.launch({
headless: false,
env: {
"DISPLAY": ":99"
}
});
const context = await browser.newContext({ javaScriptEnabled: true });
const page = await context.newPage();
await page.goto("http://www.google.com");
await page.waitForLoadState("load");
return "Yay";
}
}
Dockerfile:
FROM ubuntu:20.04 AS BUILD_IMAGE
# INSTALL NODE
RUN apt-get update && apt-get install -y \
curl
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt-get install nodejs -y
ENV NODE_ENV production
# Set up our work directory again
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# copy the source code to build the next
# server for production
COPY . .
RUN npm run build
# Remove all the development dependencies since we don't
# need them to run the actual server.
RUN rm -rf node_modules
RUN npm ci --production --ignore-scripts
# END OF BUILD IMAGE
# This starts our application's run image - the final output of build.
FROM ubuntu:20.04
# INSTALL NODE
RUN apt-get update && apt-get install -y \
curl
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt-get install nodejs -y
ENV NODE_ENV production
RUN addgroup -gid 1001 --system nodejs
RUN adduser --system nestjs -u 1001
# Pull the built files out of BUILD_IMAGE - we need:
# 1. the package.json and package-lock.json
# 2. the Nest build output
# 3. the node_modules.
WORKDIR /app
COPY --from=BUILD_IMAGE --chown=nestjs:nodejs /app/package.json /app/package-lock.json ./
COPY --from=BUILD_IMAGE --chown=nestjs:nodejs /app/node_modules ./node_modules
COPY --from=BUILD_IMAGE --chown=nestjs:nodejs /app/dist ./dist
RUN npx playwright install-deps
RUN apt-get install xvfb
RUN apt-get install x11-apps -y
RUN apt-get install screen -y
RUN screen -d -m Xvfb -ac :99 -screen 0 1280x1024x16
ENV DISPLAY :99
USER nestjs
WORKDIR /app
RUN npx playwright install
# Bind the server to 0.0.0.0:3000 on the assumption that
# firewalls in the VPC and container will prevent abuse of 0.0.0.0.
ENV PORT 3000
ENV HOST 0.0.0.0
EXPOSE 3000
CMD [ "npm", "run", "start:prod" ]
The problem: When invoking playwright via an http request, it output the error:
╔═════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Looks like you launched a headed browser without having a XServer running. ║
║ Set either 'headless: false' or use 'xvfb-run <your-playwright-app>' before running Playwright. ║
║ ║
║ <3 Playwright Team ║
╚═════════════════════════════════════════════════════════════════════════════════════════════════╝
From what I understand, the RUN screen -d -m Xvfb -ac :99 -screen 0 1280x1024x16
should have the XServer running. Checking via bash shows that $DISPLAY
is :99
. Why would playwright be unable to see the running XServer?
EDIT: This is the same result when invoking chrome from command line:
/home/nestjs/.cache/ms-playwright/chromium-1000/chrome-linux/chrome --no-sandbox
[419:419:0510/011729.759292:ERROR:ozone_platform_x11.cc(247)] Missing X server or $DISPLAY
[419:419:0510/011729.759331:ERROR:env.cc(225)] The platform failed to initialize. Exiting.