wkhtmltopdf on Heroku: evaluating different installation options

Jacek Galanciak

January 09, 2019

ruby,rails,heroku

The easiest and most flexible way of rendering fancy PDFs is using HTML+CSS as your source. wicked_pdf and pdfkit, the most popular Rails gems, employ wkhtmltopdf under the hood to generate them. It seems that there are multiple options of running wkhtmltopdf on Heroku. This post will explore them, analyze their drawbacks and identify the most reliable one.

Method 1: Apt package

First thing that comes to mind is installing wkhtmltopdf package from Ubuntu Apt repositories. The easiest way of doing this is using apt buildpack (provided by Heroku):

1heroku buildpacks:add --index 1 heroku-community/apt

Next, create Aptfile file in your project's root directory with the following content:

1wkthmltopdf

Finally, push the code to Heroku.

The build phase will list all dependencies required to install wkhtmltopdf. The package depends on audio libraries, low-level USB libraries (!), X11 and GTK libs, etc. Once the deployment completes, we can test our setup:

1heroku run bash -a YOURAPPNAME

Once the one-off dyno boots up, run:

1$ wkhtmltopdf https://www.ruby-lang.org/en/ ruby.pdf
2This application failed to start because it could not find or load the Qt platform plugin "xcb"
3in "".
4
5Reinstalling the application may fix this problem.
6Aborted

Even though the Apt package downloaded so many dependencies, it was still not enough to successfully run wkhtmltopdf.

Even if this solution worked, it would be extremely inefficient: the application's slug size increased by 146 MB. It's crucial to keep slug size small as it affects not only deployment time but also time required to boot up any dyno (resources defined in Procfile, one-off dynos with rails console etc.).

TL;DR: apt package prohibitively increases bundle size and still doesn't work. Avoid.

Method 2: buildpack

This option provides wkhtmltopdf binary as a buildpack. There are a few different buildpacks around, the most popular (and up-to-date) being dscout/wkhtmltopdf-buildpack. It's important to note that the latest version of wkhtmltopdf is 0.12.6, while this buildpack offers at most 0.12.4.

1heroku buildpacks:add https://github.com/dscout/wkhtmltopdf-buildpack.git
2heroku config:set WKHTMLTOPDF_VERSION="0.12.4"

This option increases slug size by 55.6 MB.

Note for heroku-18 / heroku-20 stack users: if your HTML source references external resources fetched over https, they will not appear on the PDF due to SSL error caused by a missing library. To resolve this issue, add apt buildpack and add the following package to your Aptfile:

1libssl1.0.0

In total, using wkhtmltopdf buildpack with libssl increases the bundle size by 56.9 MB. This increase is passable, but not perfect. The buildpack also includes wkhtmltoimage binary. If you don't need it, you're still going to have it in your app slug, unnecessarily increasing its size.

TL;DR: fast and reliable method, with moderate slug size increase; lacks the latest version.

Method 3: Ruby gem bundling the wkhtmltopdf binary

There are three popular options:

  1. wkhtmltopdf-binary — provides version 0.12.6 for macOS, Linux 32bit and Linux 64bit. Not recommended for Heroku: the gem bundles three binaries and we need only one. Each binary is about 40 MB so the slug size would increase significantly. Fine for development.
  2. wkhtmltopdf-binary-edge — offers the latest version (0.12.6) but like the previous option, contains three binaries. Even the author recommends something else for Heroku. Good for development.
  3. wkhtmltopdf-heroku — offers a single Linux binary suitable for running on Heroku.

Your Gemfile could look like this:

1group :production do
2 gem 'wkhtmltopdf-heroku'
3end
4
5group :development do
6 gem 'wkhtmltopdf-binary-edge'
7end

If your application is deployed on heroku-18 stack, you'll also need to add libssl1.0.0 to your Aptfile to be able to fetch external resources over https.

This method appears to be extremely size-efficient: slug size increased only by 14 MB (15.9 MB with libssl).

TL;DR: Reliable and size-efficient way offering the latest version. Recommended.

Note about binary files security

Pay particular attention when dealing with any externally-downloaded binaries. We can assume that packages downloaded from Apt repository are adequately verified. What about the buildpack? We can check in its compile phase that it downloads the files from official releases section on GitHub. That is a trusted way to download the official binary.

Finally, the gems. They merely bundle the binaries but provide no proof that they were not maliciously modified. While you should always be grateful to open source developers for their contributions, it's always a good idea to verify that the binary files are the originals provided by wkhtmltopdf maintainers. Hint: download proper .deb file (xenial for heroku-16, bionic for heroku-18), extract the package and make sure (using diff or at least openssl dgst -sha256) that the binaries are identical.

Summary

We evaluated different options of installing wkhtmltopdf on Heroku for your Ruby apps. Using wkhtmltopdf-heroku gem is the most efficient option. Before you deploy any bundled binary to production, make sure to verify that it's the original binary provided by the wkhtmltopdf maintainers.

Jacek Galanciak © 2023