Hello, I’m creating a web site that needs to generate PDF files. I decided to use wkhtmltopdf (through pdf-generator library). When trying to deploy my application to fly.io I’m getting an error because it needs the wkhtmltopdf executable. Any way of doing this? is it even possible?
Thanks.
What kind of app are you running? You should be able to add wkhtmltopdf
to your app image. If you’re using a Dockerfile it might even be easy.
Thanks Kurt, your response pointed me to the right direction and I got it working now.
The app is an internal invoice system for my company.
Thanks again for your help. Fly.io is indeed great.
How did you solve it?
This took me a long time to get working due to all the dependencies wkhtmltopdf has. Here’s my Dockerfile:
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.2
ARG BUNDLER_VERSION=2.4.12
FROM ruby:$RUBY_VERSION-slim as base
LABEL fly_launch_runtime="rails"
# Rails app lives here
WORKDIR /rails
# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_WITHOUT="development:test" \
BUNDLE_DEPLOYMENT="1"
# Update gems and bundler
RUN gem update --system --no-document && \
gem install -N bundler -v "${BUNDLER_VERSION}"
# Install packages needed to install nodejs
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install Node.js
ARG NODE_VERSION=16.13.2
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
/tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
rm -rf /tmp/node-build-master
# Latest releases available at https://github.com/aptible/supercronic/releases
ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.24/supercronic-linux-amd64 \
SUPERCRONIC=supercronic-linux-amd64 \
SUPERCRONIC_SHA1SUM=6817299e04457e5d6ec4809c72ee13a43e95ba41
RUN curl -fsSLO "$SUPERCRONIC_URL" \
&& echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \
&& chmod +x "$SUPERCRONIC" \
&& mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \
&& ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic
# You might need to change this depending on where your crontab is located
COPY crontab crontab
# Throw-away build stage to reduce size of final image
FROM base as build
# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libpq-dev node-gyp pkg-config python-is-python3
# Install yarn
ARG YARN_VERSION=1.22.10
RUN npm install -g yarn@$YARN_VERSION
# Build options
ENV PATH="/usr/local/node/bin:$PATH"
# Install application gems
COPY --link Gemfile Gemfile.lock ./
RUN bundle install --without development test && \
rm -rf ~/.bundle/ $BUNDLE_PATH/ruby/*/cache $BUNDLE_PATH/ruby/*/bundler/gems/*/.git
# Install node modules
# COPY --link package.json yarn.lock ./
# RUN yarn install --frozen-lockfile
# Copy application code
COPY --link . .
# Adjust binfiles to set current working directory
RUN grep -l '#!/usr/bin/env ruby' /rails/bin/* | xargs sed -i '/^#!/aDir.chdir File.expand_path("..", __dir__)'
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
# RUN SECRET_KEY_BASE=DUMMY ./bin/rails assets:precompile
# Final stage for app image
FROM base
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y postgresql-client && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install wkhtmltopdf
RUN apt update && apt -y upgrade
RUN apt install -y wget
RUN wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_amd64.deb
RUN apt install -y \
fontconfig \
libfreetype6 \
libjpeg62-turbo \
libpng16-16 \
libx11-6 \
libxcb1 \
libxext6 \
libxrender1 \
xfonts-75dpi \
xfonts-base
RUN apt install -y ./wkhtmltox_0.12.6-1.buster_amd64.deb \
&& rm ./wkhtmltox_0.12.6-1.buster_amd64.deb \
&& chmod +x /usr/local/bin/wkhtmltopdf
# Run and own the application files as a non-root user for security
ARG UID=1000 \
GID=1000
RUN groupadd -f -g $GID rails && \
useradd -u $UID -g $GID rails --home /rails --shell /bin/bash
USER rails:rails
# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build --chown=rails:rails /rails /rails
# Deployment options
ENV RAILS_LOG_TO_STDOUT="1" \
RAILS_SERVE_STATIC_FILES="true"
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
The relevant portion:
# Install wkhtmltopdf
RUN apt update && apt -y upgrade
RUN apt install -y wget
RUN wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_amd64.deb
RUN apt install -y \
fontconfig \
libfreetype6 \
libjpeg62-turbo \
libpng16-16 \
libx11-6 \
libxcb1 \
libxext6 \
libxrender1 \
xfonts-75dpi \
xfonts-base
RUN apt install -y ./wkhtmltox_0.12.6-1.buster_amd64.deb \
&& rm ./wkhtmltox_0.12.6-1.buster_amd64.deb \
&& chmod +x /usr/local/bin/wkhtmltopdf
You could also try this:
RUN apt install -y --no-install-recommends wkhtmltopdf
I agree with @ben-io
@elpavohombre you should have been able to do this with:
bin/rails generate dockerfile --add=wkhtmltopdf
Did you do this by calling wkhtmltopdf directly (e.g., using backtics or Open3)? Or did you use a gem? If the latter, I’d like to make this easier for people going forward by either automatically detecting the presence of a dependent gem and adding wkhtmltopdf for you. I already do this with grover (and puppeteer in general).