If you’re generating PDFs from HTML in the Laravel world, you’re likely using something like Snappy, wrapped conveniently in a service provider by barryvdh/laravel-snappy.

Snappy depends on the wkhtmltopdf binary to function. Per the documentation, this binary is conveniently available via Composer:

composer require h4cc/wkhtmltopdf-i386 0.12.x
Code language: JavaScript (javascript)

But that package hasn’t been updated in 4+ years, meaning the binary is a bit out of date. You’re much better off with the latest and greatest version. To do that, you’ll have to install it on your server yourself. The general instructions can be found here, but I’ll outline how to set it up in a simple, automated way in your development environments, plus on Laravel Forge.

Installing wkhtmltopdf on Laravel Homestead

If you’re developing locally on Laravel Homestead, you can tinker with the included after.sh script to do some extra provisioning for your VM. Pop open after.sh and add the following, assuming you’re running the latest Homestead, which runs Ubuntu 20.04 (Focal):

sudo apt-get update sudo apt-get install -y xfonts-75dpi wget wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb \ sudo apt install -y ./wkhtmltox_0.12.6-1.focal_amd64.deb rm ./wkhtmltox_0.12.6-1.focal_amd64.deb
Code language: JavaScript (javascript)

Of course, you can run these manually on your Homestead server after provisioning, or on any other Ubuntu 20.04 install. But by putting it in after.sh, it should survive updates to your Homestead environment. Your wkhtmltopdf setup is now persistent and ready-to-go every time.

Installing wkhtmltopdf on Laravel Forge

For Laravel Forge, create a new recipe using the exact same code we used for Homestead. Run that recipe against any server hosting projects that use Snappy.

This isn’t as elegant because you still need to remember to run this if you provision a new server for the project. Forge is very good for simple things, but if more automation in this provisioning is a concern for you, look into more configurable provisioning services.

Installing wkhtmltopdf on Laravel Sail

Laravel Sail is a bit different than Homestead in that your dev environment is Docker-driven, so there are existing strategies for provisioning, unlike Homestead’s arbitrary after.sh.

First, if you haven’t already, you need to publish Sail’s Dockerfiles. Done via artisan:

sail artisan sail:publish
Code language: CSS (css)

This will create a new docker directory in the root of your project, with both PHP 7.4 and 8.0 configurations. Your existing docker-composer.yml file should have one of those declared already. Also note that it will have been automatically updated to reference the new docker directory:

# For more information: https://laravel.com/docs/sail version: '3' services: laravel.test: build: context: ./docker/8.0 dockerfile: Dockerfile args: WWWGROUP: '${WWWGROUP}' image: sail-8.0/app ports: - '${APP_PORT:-80}:80' environment: WWWUSER: '${WWWUSER}' LARAVEL_SAIL: 1 volumes: - '.:/var/www/html' networks: - sail depends_on: - mysql mysql: image: 'mysql:8.0' ports: - '${FORWARD_DB_PORT:-3306}:3306' environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' volumes: - 'sailmysql:/var/lib/mysql' networks: - sail healthcheck: test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] retries: 3 timeout: 5s networks: sail: driver: bridge volumes: sailmysql: driver: local
Code language: PHP (php)

Go ahead and open the Dockerfile referenced in your docker-compose.yml file. It isn’t terribly important where you add the following, but I’ve added mine after pecl dependencies are installed.

RUN pecl channel-update https://pecl.php.net/channel.xml \ && pecl install swoole \ && pecl clear-cache \ && rm -rf /tmp/* /var/tmp/* RUN apt-get update \ && apt-get install -y xfonts-75dpi wget \ && wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb \ && apt install -y ./wkhtmltox_0.12.6-1.focal_amd64.deb \ && rm ./wkhtmltox_0.12.6-1.focal_amd64.deb RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.0
Code language: JavaScript (javascript)

And finally, rebuild your container:

sail build --no-cache

What I love about this, and Sail / Docker in general, is that this is now ready to go for you every time you start development on this project, with no dependence on a pre-configured development environment. You never have to think about it again.

Either Way: Finishing Up

Last thing, make sure your project is using the right version of wkhtmltopdf. By default, laravel-snappy looks in /usr/local/bin/wkhtmltopdf, which is where this gets installed. SSH into your environment and verify the location and version:

[email protected]:/var/www/html$ which wkhtmltopdf /usr/local/bin/wkhtmltopdf [email protected]:/var/www/html$ wkhtmltopdf --version wkhtmltopdf 0.12.6 (with patched qt)
Code language: JavaScript (javascript)

If, for some reason, the binary has ended up elsewhere, be sure to update your .env file to point to the new wkhtmltopdf binary:

WKHTMLTOPDF_BINARY=/some/other/path/wkhtmltopdf
Code language: JavaScript (javascript)

And you’re all set! Happy coding.

Leave a Comment