wkhtmltopdf on Heroku: evaluating different installation options
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.pdf2This application failed to start because it could not find or load the Qt platform plugin "xcb"3in "".45Reinstalling 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.git2heroku 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:
- 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.
- 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.
- wkhtmltopdf-heroku — offers a single Linux binary suitable for running on Heroku.
Your Gemfile
could look like this:
1group :production do2 gem 'wkhtmltopdf-heroku'3end45group :development do6 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.