↓ Skip to main content

How to Install Pa11y on a DigitalOcean Droplet

·778 words·4 mins
Author
Alessandro Ferrini

Historical setup: These notes describe the original test on Ubuntu 24.10 with Chrome 127.0.6533.88, not a current deployment recommendation. Ubuntu 24.10 reached end of life on 10 July 2025, and Chrome 127 is obsolete. Re-test the procedure on supported software before using it for a new deployment.

Installing Pa11y on a virtual machine turned out to be more challenging than I expected, and since I couldn’t find many guides online I decided to write one. I’ve included the original installation script, with its limitations below.

What Is Pa11y?
#

Pa11y as described by its team is an automated accessibility testing pal. In other words, it helps identify accessibility issues on websites. The European Accessibility Act has applied to specified products and services since 28 June 2025, including e-commerce services. Exemptions and transitional provisions apply.

Further Reading: For a detailed overview, check out Martijn Hols’s excellent article: The European Accessibility Act for websites and apps.

For a personal project, I need an API to scan a website and return a JSON response with accessibility issues detected by the automated checks. Automated checks do not replace manual evaluation or certify compliance. Fortunately, Pa11y can output results in JSON. For instance, running:

pa11y https://www.alessandroferrini.com -r json

produces a JSON-formatted list of accessibility issues. Perfect!

The Problem
#

Installing Pa11y on my local machine was simple: npm install -g pa11y. However, when I tried to deploy my application to a virtual machine, everything stopped working. My stack is straightforward FastAPI for an API endpoint and Redis for caching, but on the VM, I encountered so many cryptic errors that it was difficult to identify the root cause.

Installing Pa11y on DigitalOcean
#

For the original tests, I used a $4/month Droplet with 512 MB of RAM from DigitalOcean with Ubuntu 24.10.

  1. Configure a VM:
    I bought a Droplet on DigitalOcean and created a new user. If you’re not sure how to do this, consult their official guide: How to Add and Delete Users on Ubuntu.

  2. Install explicit historical versions:

    In my case, I installed Chrome 127.0.6533.88 because newer versions gave me trouble. The versioned example below pairs Pa11y 8.0.0 with Puppeteer 22.15.0, whose Chrome revision is 127.0.6533.88. Pa11y 8 documented support for Node.js 18, 20, and 22. The original notes did not record the Node.js or Pa11y versions: these pins make the dependencies explicit, but are not a newly tested VM configuration. Pa11y 8 is also out of support; for a new installation, follow the maintained combinations in the Pa11y requirements and support table.

    export TARGET_CHROME_VERSION="127.0.6533.88"
    sudo npm install -g pa11y@8.0.0
    npx puppeteer@22.15.0 browsers install "chrome@$TARGET_CHROME_VERSION"
  3. Select the downloaded browser explicitly:

    Downloading Chrome alone does not tell Pa11y to use it. Save the following as pa11y.config.js; chromeLaunchConfig.executablePath selects the executable in the Linux user’s Puppeteer cache.

    module.exports = {
      chromeLaunchConfig: {
        executablePath: `${process.env.HOME}/.cache/puppeteer/chrome/linux-${process.env.TARGET_CHROME_VERSION}/chrome-linux64/chrome`
      }
    };

    Run Pa11y as the user who downloaded Chrome, in the same shell where TARGET_CHROME_VERSION was exported:

    pa11y https://www.alessandroferrini.com --config pa11y.config.js -r json

Historical workarounds, not installation steps
#

Do not apply system changes to every VM. Reproduce and diagnose the corresponding error first:

  • Sandbox errors: If Chrome reports No usable sandbox!, consult the Puppeteer troubleshooting guide. It labels the setuid sandbox instructions as mostly out of date. If an older setup genuinely requires that sandbox, the documented ownership is root:root and the mode is 4755, not 4775. Do not disable the sandbox to bypass the error.
  • Session errors: If logs report a missing runtime directory or D-Bus session, check that the session and its resources actually exist. Setting XDG_RUNTIME_DIR or DBUS_SESSION_BUS_ADDRESS only points to those resources; it does not create them. Exporting those variables blindly is not an installation fix.
  • Memory allocation errors: vm.overcommit_memory=1 changes a system-wide kernel policy, not a Pa11y option. Investigate actual allocation failures and memory limits before considering it; a small Droplet alone is not a reason to change the policy.

TL;DR
#

I wrote a small script for the original setup. Besides installing packages, it runs apt upgrade, changes a kernel parameter, and modifies .bashrc. It still installs an unpinned Pa11y version and applies the old sandbox workaround; it has not been updated by the corrections in these notes.

Caution: Always review any script from the internet before running it. Do not run this historical script unchanged on a production machine; adapt it to supported software and your diagnosed requirements first.

Download and read it without executing it:

wget -O install.sh https://raw.githubusercontent.com/Alurith/pa11y-digital-ocean/refs/heads/main/install.sh
less install.sh

Only after reviewing and adapting the downloaded file, run it separately:

bash install.sh

If you encounter a problem, open an issue on GitHub.

If you want to support more tests this is my referral link to DigitalOcean, thanks!