How To Enable Hardware Acceleration on Chrome, Chromium & Puppeteer on AWS in Headless mode
Tags: aws, headle, chrome, gpu
Published: 2023-10-25 13:51:22

> How We Enhanced Remotion Performance through GPU-Accelerated Server-Side Rendering

Running [Google Chrome](https://developer.chrome.com/blog/headless-chrome/) with hardware acceleration in headless mode can be more challenging than it appears. We embarked on this journey with [Remotion](https://remotion.dev), which is an excellent framework that enables developers to "Make Videos Programmatically". On our way, explore various Nvidia driver versions, including those from Nvidia's website and Ubuntu's official repositories.

We collaborated with the vibrant [Remotion](https://remotion.dev) Open-source community to find the answer for using [GPU with Remotion for server-side rendering](https://github.com/remotion-dev/remotion/issues/2889). After encountering some setbacks on our way, we were able to make it work for Remotion eventually. We consolidated our findings in the Remotion Docs at [Using the GPU in the Cloud](https://remotion-git-gpu-on-ec2-remotion.vercel.app/docs/miscellaneous/cloud-gpu) and simplified the instructions for Remotion developers to make the most out of it. Although the whole research was done for [Remotion](https://remotion.dev), the same process will work for any headless application that requires GPU power, especially in headless mode.

### **Hardware Acceleration in Browser Rendering**

Hardware Acceleration is to your browser what "**Nitrogen Fuel**" is for a gasoline car. It uses the power of specialized hardware like GPUs to make your web pages load faster and videos play smoothly. Hardware acceleration improves the part where the web page is displayed and shown to you, known as rendering. This results in a smoother and snappier browsing experience.

### DLAMI from Marketplace?

One may wonder why we didn't opt for the AWS Deep Learning AMI or DLAMI. But we needed fine-grained control over the GPU drivers and utilities, and the outdated DLAMIs despite all the bloatware was not the answer. Such tasks are often challenging to achieve with pre-packaged AMIs as discussed in "[Why Deep Learning AMI is Holding You Back](https://mirzabilal.com/why-your-aws-deep-learning-ami-is-holding-you-back-and-how-to-fix)". Tailoring the environment to our exact requirements also helped us troubleshoot issues effectively.

We experimented with multiple packages, to identify the key ones needed for Google Chrome to recognize the GPU. Despite these efforts, GPU recognition remained elusive, and in some instances, GPU drivers were crashing even at initialization. The long and arduous journey has brought us to the end of the tunnel, yet the darkness persists, and the solution remains as elusive as ever. As we decided to call it a day, We stumbled upon [this thread](https://github.com/puppeteer/puppeteer/issues/3637) on [Puppeteer](https://pptr.dev)'s Github issues, which did not give us any hope, but did give us a new perspective and drive to achieve our goal.


![Developers are facing similar issues with hardware acceleration in headless mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmh1l1gpmzn5k9ssvfaj.png)

## **The Fresh Start**

It was time to return to the drawing board and start afresh. We started with a clean base Ubuntu AMI on AWS EC2 Instance. After that, we downloaded and installed the Nvidia Tesla T4G drivers from Nvidia's official website.

Once confirmed that the GPU was working properly using `nvidia-smi`, We installed Google Chrome and tested it for hardware acceleration, to our relief Google Chrome finally gave a nod to work with Hardware Acceleration.

## Launching an EC2 Instance

Launching an EC2 instance can be achieved in various ways, with the AWS Web Console and AWS CLI being two notable options. Regardless of the method, the important parameters are instance type and AMI selection. At the time of writing, the AMI ID for our chosen instance `g4dn.xlarge` is `ami-053b0d53c279acc90`. For launching the EC2 instance via `aws-cli`, the following command can be used, after replacing the placeholders with actual values.

```bash
aws ec2 run-instances \
  --instance-initiated-shutdown-behavior "terminate" \
  --image-id "ami-053b0d53c279acc90" \
  --instance-type "g4dn.xlarge" \
  --key-name "<KEY_NAME>" \
  --subnet-id "<SUBNET_ID>" \
  --security-group-ids "<SECURITY_GROUP_ID>" \
  --iam-instance-profile Arn="<ARN>" \
  --block-device-mappings '[
  {
    "DeviceName": "/dev/sda1",
    "Ebs": {
      "VolumeSize": 8,
      "VolumeType": "gp3"
    }
  }
]'
```

## Ubuntu Upgrade

Ubuntu 22.04 AMI `ami-053b0d53c279acc90` on AWS comes with Linux Kernel `v5` (specifically `5.19.0-1025-aws`). At this point, we have two options either we stick with Kernel `v5` or Upgrade to `v6` (`v6.2.0-1013-aws`), we decided to upgrade the Kernel. This decision is crucial as the Nvidia driver compiled for one version will not work for the other.

After launching the instance, SSH into the instance and initiate the Ubuntu packages upgrade process. To update all the installed packages including Linux Kernel execute the following one-liner.

```bash
sudo bash -c "apt update && export DEBIAN_FRONTEND=noninteractive && export NEEDRESTART_MODE=a && apt upgrade -y && reboot"
```

We can also split `apt update`, `apt upgrade -y` and `reboot`. But the reason behind doing it like this is to install these updates in non-interactive mode.

After the execution, the system will reboot with Linux Kernel Version 6. We can confirm the kernel update with `uname -r`. Rebooting is essential when upgrading the Ubuntu system because it loads the new Kernel on the next boot, and Nvidia drivers will subsequently be built for the updated version.

## **Nvidia GPU Driver Installation**

The process of installing GPU drivers is straightforward when we have the correct driver for the GPU and the corresponding compatible version. Before starting the installation we need to install a couple of packages: `build-essential` and `libvulkan1` . The former is a bundle with a variety of compilation tools required to compile the Nvidia driver. The latter, while not mandatory, is required by Google Chrome. Therefore it's a good idea to install it beforehand to enable support for Vulkan ICD loader for Nvidia, should we require it in the future.

```bash
sudo apt install -y build-essential libvulkan1
```

After build tools are installed, we can proceed to download and install the GPU drivers using the following commands:

```bash
DRIVER_URL="https://us.download.nvidia.com/tesla/535.104.12/NVIDIA-Linux-x86_64-535.104.12.run"
DRIVER_NAME="NVIDIA-Linux-driver.run"
wget -O "$DRIVER_NAME" "$DRIVER_URL"
sudo sh "$DRIVER_NAME" --disable-nouveau --silent
rm "$DRIVER_NAME"
```

Now we can run `nvidia-smi` to confirm the GPU drivers installation. The output will look similar to this:


![nvidia-smi output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gm1ig2rq3b6hzs0pqq3p.png)

### **Configuring the Startup Service**

We learned this the hard way: running `nvidia-smi` once is needed for the proper initialization of `EGL` and `ANGLE`. Google Chrome and Chromium fail to initialize `EGL` without this preliminary setup. To automate this process, we will create a service that runs `nvidia-smi` at boot time using following commands:

```bash
echo '[Unit]
Description=Run nvidia-smi at system startup

[Service]
ExecStart=/usr/bin/nvidia-smi
Type=oneshot
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target' | sudo tee /etc/systemd/system/nvidia-smi.service
sudo systemctl enable nvidia-smi.service
sudo systemctl start nvidia-smi.service
```

## Testing the Installation

To test hardware acceleration with Google Chrome or Chromium, we can follow these steps. It's worth noting that Google Chrome has more dependencies, making it an easier choice if we plan to use the Node.js library, Puppeteer.

On the other hand, Chromium is a lightweight option with a smaller footprint of dependencies, but we can still use Puppeteer with Chromium by installing a few extra dependencies.

### Chromium

* #### Installation:
    
    Installing Chromium is straightforward, as it is readily available with Ubuntu's official software repositories. We can install it using `apt` with the following command.
    

```bash
sudo apt install -y chromium-browser
```

* #### Testing:
    
    Chromium is fully prepared to handle Hardware Acceleration tasks. We can verify its readiness by launching Chromium with the specified parameters.
    

```bash
chromium-browser --headless --use-gl=angle \
   --use-angle=gl-egl --use-cmd-decoder=passthrough \
   --print-to-pdf=output.pdf 'chrome://gpu'
```

To use Puppeteer with Chromium instead of Google Chrome, there are a few extra dependencies that should be installed.

```bash
sudo apt install ca-certificates fonts-liberation \
    libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 \
    libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 \
    libgbm1 libgcc1 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 lsb-release wget xdg-utils
```

### Google Chrome

* #### Installation:
    
    Google Chrome can be installed from multiple options, but we will use the Google Chrome official repository for Debian. We need to add it to Ubuntu's repo list along with the public signing key.
    

```bash
curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/googlechrom-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrom-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list
sudo apt update
sudo apt install -y google-chrome-stable
```

* #### Testing:
    
    Google Chrome is ready for our Hardware Acceleration tasks. We can test it by launching Google Chrome with the following parameters.
    

```bash
google-chrome-stable --headless --use-gl=angle \
    --use-angle=gl-egl --use-cmd-decoder=passthrough \
    --print-to-pdf=output.pdf 'chrome://gpu'
```

The above commands will generate `output.pdf`, and transfer it to your local machine to check the status of Hardware Acceleration in Google Chrome or Chromium. If the process went smoothly, the resultant `PDF` will look like this.

![Chrome GPU status screenshot.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bphbiqpu6shcbwj0jbau.png)

## Working with Puppeteer

To verify GPU acceleration using the Node.js library Puppeteer, follow these steps:

* Install Node.js, as this clean Ubuntu AMI does not include any unnecessary packages. Use the following commands:
    

```bash
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
NODE_MAJOR=18
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
sudo apt update
sudo apt install nodejs
```

* After installing Node.js, we can install Puppeteer by running `npm i puppeteer` in our code directory. Here's a sample `index.js` file for checking hardware acceleration:
    

```javascript
const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch({
    headless: true, 
    args: ['--use-gl=angle', '--use-angle=gl-egl'], 
  });
  const page = await browser.newPage();
  await page.goto('chrome://gpu');
  await page.waitForTimeout(2000);
  await page.screenshot({ path: 'output.png' });
  await browser.close();
})();
```

* Run the script using `node index.js`. This will generate an `output.png` file containing hardware acceleration information.
    

## Note from the Creator

> [Mirza](https://mirzabilal.com) has been immensely helpful in helping the “[Remotion](https://remotion.dev)” community adopt GPU-accelerated rendering.  
> He's researched and written about how to obtain, configure and run EC2 containers and headless Chrome correctly in order to take advantage of graphics acceleration.  
> This area has been especially hard to crack, and without Mirza we would not have been able to unlock huge speed boosts.
> 
> We are super grateful for that!
> 
> \--  
> [Jonny Burger](https://jonny.io)  
> Creator / [Remotion.dev](http://Remotion.dev)

## Conclusion

With hardware acceleration now readily available in headless mode, we can harness the power of GPUs for faster and more complex rendering tasks. Our next steps involve creating a custom AMI from this instance and streamlining the process using AWS Image Builder Pipelines for efficiency. Additionally, we plan to extend hardware capabilities to Docker containers, further extending our options.

## Resources

* **Remotion - Make videos programmatically:**
    
    [https://remotion.dev](https://remotion.dev)
    
* **Remotion - Using the GPU in the cloud:**
    
    [https://www.remotion.dev/docs/miscellaneous/cloud-gpu](https://www.remotion.dev/docs/miscellaneous/cloud-gpu)
    
* **Cannot enable GPU acceleration:**
    
    [*https://github.com/puppeteer/puppeteer/issues/3637*](https://github.com/puppeteer/puppeteer/issues/3637)
    
* **Recommend a workflow for using the GPU on a AWS instance**:
    
    [https://github.com/remotion-dev/remotion/issues/2889](https://github.com/remotion-dev/remotion/issues/2889)
    
* **Getting Started with Headless Chrome:**
    
    [*https://developer.chrome.com/blog/headless-chrome/*](https://developer.chrome.com/blog/headless-chrome/)
    
* **Why Your AWS Deep Learning AMI is Holding You Back and How to Fix:**
    
    [*https://mirzabilal.com/why-your-aws-deep-learning-ami-is-holding-you-back-and-how-to-fix*](https://mirzabilal.com/why-your-aws-deep-learning-ami-is-holding-you-back-and-how-to-fix)
    
* **Deep Learning with “AWS Graviton2 + NVIDIA Tensor T4G” for as low as free\* with CUDA 12.2:**
    
    [*https://mirzabilal.com/deep-learning-with-aws-graviton2-nvidia-tensor-t4g-for-as-low-as-free-with-cuda-12-2-56d8457a6f6d*](https://mirzabilal.com/deep-learning-with-aws-graviton2-nvidia-tensor-t4g-for-as-low-as-free-with-cuda-12-2-56d8457a6f6d)
    
* **How to install FFmpeg with Harware Accelaration on AWS:**
    
    [*https://mirzabilal.com/how-to-install-ffmpeg-with-harware-accelaration-on-aws*](https://mirzabilal.com/how-to-install-ffmpeg-with-harware-accelaration-on-aws)
    
* **CPU vs GPU for Video Transcoding - Challenging the Cost-Speed Myth:**
    
    [https://mirzabilal.com/cpu-vs-gpu-for-video-transcoding-challenging-the-cost-speed-myth](https://mirzabilal.com/cpu-vs-gpu-for-video-transcoding-challenging-the-cost-speed-myth)