Make Nokogiri use system libxml2

Updated . Posted . Visible to the public. Repeats.

The nokogiri Show archive.org snapshot gem provides different packages for several platforms. Each platform-specific variant ships pre-built binaries of libxml2, e.g. x86_64-linux includes binaries for 64bit Linux on Intel/AMD. This significantly speeds up installation of the gem, as Nokogiri no longer needs to compile libxml2.

However, this also means that for each security issue with libxml2, Nokogiri maintainers have to update their pre-built binaries and release a new version of the gem. Then, you need to update and deploy each of your applications that are using nokogiri.

There were numerous security issues with libxml2 in the past, and we maintain a lot of applications.
We want to use our (regularly updated) system libraries because of that.

# Quick check
Nokogiri::VersionInfo.instance.libxml2_using_system?

Instructions

Nokogiri can compile its C extensions against system libraries, but if any matching pre-built binaries are available, it will not compile anything. Hence, we need a variant without binaries.

The following steps summarize what the Nokogiri documentation covers Show archive.org snapshot , with some added explanations.

  1. Force installing the ruby platform variant of the nokogiri gem.

    In your Gemfile, specify the force_ruby_platform option for the gem. This will download the ruby variant which includes no binaries, only the libxml2 extension source.

    gem 'nokogiri', force_ruby_platform: true
    

    If you are on Bundler < 2.3.18, either upgrade Bundler (if possible) or use the alternative approaches from the nokogiri docs Show archive.org snapshot .

  2. Make sure that the --use-system-libraries build option is set when installing the nokogiri gem.

    If the --use-system-libraries flag is not set, Nokogiri will compile libxml2 from its included sources. This is the same as using the pre-built binaries, just slower to install.

    Our application environments

    If you are a makandra employee and are running your app on makandra servers, you can skip this step.
    All servers and developer machines at makandra are already configured using the global Bundler configuration.

    You need to specify that using the Bundler configuration, either globally, or locally (per project).

    • Locally:

      bundle config --local build.nokogiri --use-system-libraries
      

      This writes to a file .bundle/config in your project directory. Ensure that it is not gitignored, or your changes are only valid for your machine, not any servers. Inside a Docker environment, this file might be ignored. How to fix.

    • Globally:

      bundle config --global build.nokogiri --use-system-libraries
      

      This writes to a file in your user home, ~/.bundle/config.
      Use this approach only when your servers are configured the same way, or when they use matching env variables.

  3. Make sure your Gemfile.lock has a correct settings for PLATFORMS

  4. Install gems.

    bundle install
    

    If you were already using the ruby variant of Nokogiri, you must re-install the gem so it compiles against system libraries.

    bundle pristine nokogiri
    
  5. Your Gemfile.lock should now only contain one entry for nokogiri (e.g. nokogiri (1.16.6)), without any platform-specific suffix.

  6. Verify that you are using you system's libxml2:

    Nokogiri::VersionInfo.instance.libxml2_using_system?
    

    You may also check Nokogiri::VersionInfo.instance.warnings for any warnings (though they should appear e.g. when launching a Rails console) or Nokogiri::VersionInfo.instance.to_hash to view more information.

    Note

    If your application uses Spring, run spring stop before verifying.

Arne Hartherz
Last edit
Dominik Schöler
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2015-12-17 12:53)