Question

Fixing Ruby Gem Native Extension Errors: mkmf.rb Can't Find Header Files for Ruby

rubyjsonrubygems

Question

I am trying to install the json gem on a remote server using a proxy. The server is behind a firewall, and I am using Ruby 1.8.7. When I run:

sudo gem install --http-proxy <host-address>:<port> json

I get this error:

Building native extensions. This could take a while...
ERROR: Error installing json:
        ERROR: Failed to build gem native extension.

/usr/bin/ruby extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib/ruby/ruby.h

Gem files will remain installed in /usr/lib64/ruby/gems/1.8/gems/json-1.8.1 for inspection.
Results logged to /usr/lib64/ruby/gems/1.8/gems/json-1.8.1/ext/json/ext/generator/gem_make.out

What does this error mean, and how can I fix it?

Short Answer

By the end of this page, you will understand why some Ruby gems need to compile native extensions, what mkmf.rb and ruby.h are, and why installation fails when Ruby development headers are missing. You will also learn the usual fix on Linux servers: installing the Ruby development package that matches your Ruby version.

Concept

Some Ruby gems are written entirely in Ruby, but others include native extensions written in C. The json gem version in your example tries to compile C code during installation.

When RubyGems installs such a gem, it usually runs:

  1. extconf.rb
  2. mkmf.rb to generate a Makefile
  3. make to compile the extension

The key problem in your error is this line:

mkmf.rb can't find header files for ruby at /usr/lib/ruby/ruby.h

Ruby header files are C header files that describe Ruby's internal API. The most important one is often ruby.h. If these files are not installed, Ruby cannot compile native gems.

This is usually not a proxy problem. The proxy affects downloading the gem, but this error happens later during local compilation.

Why this matters

In real Ruby development, many gems depend on native extensions for speed or system integration, such as:

  • json
  • nokogiri
  • pg
  • mysql2
  • ffi

If your system is missing the Ruby development package, these gems often fail with errors about:

  • ruby.h
  • mkmf.rb
  • missing compiler tools
  • failed native extension builds

The fix is usually to install the Ruby development headers and sometimes the basic build tools.

Mental Model

Think of a native gem like a machine that must be assembled before use.

  • The gem provides the machine parts.
  • extconf.rb checks whether your system has the right tools.
  • mkmf.rb writes the assembly instructions.
  • make builds the machine.
  • ruby.h is like the official blueprint for connecting that machine to Ruby.

If the blueprint is missing, the build cannot even start. That is what this error is telling you.

Take Quiz

Syntax and Examples

Typical install command

gem install json

If the gem contains native C code, RubyGems may compile it during install.

Example of the failure

Building native extensions. This could take a while...
mkmf.rb can't find header files for ruby at /usr/lib/ruby/ruby.h

This means Ruby itself is installed, but the development files for Ruby are not.

Common fix on Linux

Depending on your distribution, install the Ruby development package.

Debian or Ubuntu

sudo apt-get update
sudo apt-get install ruby-dev build-essential

For older systems or version-specific packages, it may be:

sudo apt-get install ruby1.8-dev build-essential

RHEL, CentOS, or Fedora

sudo yum install ruby-devel gcc make

Or on newer systems:

sudo dnf install ruby-devel gcc make

Then retry

sudo gem install --http-proxy <host-address>:<port> json

Why package names differ

Different Linux distributions name the development package differently:

  • ruby-dev
  • ruby-devel
  • ruby1.8-dev

The important idea is: you need the package that contains Ruby headers such as ruby.h.

Step by Step Execution

Example flow

Suppose you run:

gem install json

Here is what happens step by step:

  1. RubyGems downloads the gem.
  2. RubyGems sees that the gem includes native extension code.
  3. It runs:
ruby extconf.rb
  1. extconf.rb uses mkmf.rb to inspect your system.
  2. mkmf.rb looks for Ruby header files, including ruby.h.
  3. If the headers are missing, it stops and prints:
mkmf.rb can't find header files for ruby
  1. Because the Makefile cannot be generated, compilation never starts.
  2. The gem installation fails.

Small trace example

Command: gem install json
-> download gem
-> detect native extension
-> run extconf.rb
-> check for ruby.h
-> ruby.h missing
-> abort build
-> installation failed

So the failure is not really about JSON itself. It is about the system not being ready to compile C extensions for Ruby.

Real World Use Cases

Native extension build errors are common in real environments such as:

  • Remote Linux servers where only runtime packages were installed
  • Minimal Docker images that omit compilers and development headers
  • CI pipelines that install gems on a clean machine
  • Corporate networks where downloads go through a proxy, but local build dependencies are still missing
  • Legacy systems running older Ruby versions like 1.8.7

Practical examples:

  • Installing pg requires PostgreSQL client development libraries
  • Installing nokogiri may require XML-related build dependencies
  • Installing json may require Ruby development headers

A common lesson is that gem install may need both:

  1. network access to download the gem
  2. local development tools to compile it
Take Quiz

Real Codebase Usage

In real projects, developers usually avoid dealing with this problem manually on every machine by standardizing setup.

Common patterns

Environment bootstrap scripts

Teams often create setup scripts such as:

sudo apt-get install ruby-dev build-essential
bundle install

This makes onboarding more reliable.

Dependency documentation

Projects often document system packages in a README or setup guide, for example:

  • Ruby headers
  • compiler tools
  • database client libraries
  • OS-specific package names

CI and Docker setup

In CI or Dockerfiles, developers explicitly install build dependencies before running Bundler:

apt-get update && apt-get install -y ruby-dev build-essential
bundle install

Guarding against environment mismatch

In older codebases, version mismatches are common. For example:

  • Ruby runtime is installed
  • but matching ruby-dev package is missing
  • or the wrong version of development headers is installed

The rule is simple: the development package should match the installed Ruby version.

Common Mistakes

1. Thinking the proxy caused the header file error

The proxy may affect downloading, but this specific error happens during compilation.

Misleading assumption

gem install --http-proxy proxy:8080 json

If download succeeds and build fails with ruby.h missing, the issue is local system setup, not the proxy.

2. Installing Ruby runtime but not development files

Many systems split packages into:

  • runtime package
  • development package

Broken setup

ruby -v
# works

gem install json
# fails: can't find header files for ruby

Fix

Install ruby-dev, ruby-devel, or version-specific equivalent.

3. Missing compiler tools

Sometimes headers are installed, but gcc or make is missing.

Possible fix

sudo apt-get install build-essential

or

sudo yum install gcc make

4. Installing the wrong version of development headers

If your system has Ruby 1.8.7, but the installed headers belong to another version, builds may still fail.

Always verify the package matches your Ruby version.

5. Assuming every gem is pure Ruby

Some gems install without any compilation. Others require native builds.

Do not assume gem install only downloads files.

6. Ignoring the build log

Your error message points to a log file such as:

.../gem_make.out

That file often contains more detailed diagnostics and is one of the first places to check.

Comparisons

Ruby runtime vs Ruby development package

ItemWhat it providesNeeded to run Ruby scriptsNeeded to compile native gems
Ruby runtimeRuby interpreterYesNo
Ruby development packageHeaders like ruby.hNoYes
Build toolsgcc, makeNoYes

Pure Ruby gems vs native extension gems

Gem typeNeeds compilationCommon failure reason
Pure Ruby gemNoNetwork, permissions, version constraints
Native extension gemYesMissing headers, compiler, system libraries

Proxy issue vs build dependency issue

Problem typeTypical symptomExample
Proxy/network problemDownload fails, timeout, connection refusedCannot fetch gem from source
Build dependency problemDownload works, compile failsmkmf.rb can't find header files for ruby
Take Quiz

Cheat Sheet

Quick diagnosis

If you see:

mkmf.rb can't find header files for ruby

then usually you need:

  • Ruby development headers
  • compiler tools

Common install commands

Debian or Ubuntu

sudo apt-get install ruby-dev build-essential

Older version-specific package:

sudo apt-get install ruby1.8-dev build-essential

RHEL / CentOS / Fedora

sudo yum install ruby-devel gcc make

Retry gem installation

sudo gem install json

or with proxy:

sudo gem install --http-proxy <host-address>:<port> json

Key files and tools

  • extconf.rb — checks build environment
  • mkmf.rb — generates Makefile
  • ruby.h — Ruby C API header
  • gem_make.out — detailed build log

Rule of thumb

If a gem builds native extensions, you often need:

  1. the Ruby development package
  2. gcc
  3. make
  4. any gem-specific system libraries

FAQ

Why does gem install try to compile code?

Some gems include native extensions written in C for performance or system integration. Those gems must be compiled during installation.

What is ruby.h?

ruby.h is a C header file that defines the interface needed to build C extensions against Ruby.

Is this error caused by the proxy?

Usually no. A proxy affects downloading. This error appears after download, when the gem tries to build locally.

What package should I install?

Usually one of these, depending on your Linux distribution:

  • ruby-dev
  • ruby-devel
  • ruby1.8-dev

You may also need compiler tools like gcc and make.

Why does Ruby work even though ruby.h is missing?

Because the Ruby interpreter can run normally without development headers. The headers are only needed when compiling native extensions.

Where can I find more detail about the failure?

Check the gem_make.out file mentioned in the error output. It often contains the exact build step that failed.

Does the json gem always need native compilation?

Some versions include native extensions, while others may also provide pure Ruby code. In your case, the installation process is attempting to build a native extension.

Take Quiz

Mini Project

Description

Create a small server setup checklist for installing native Ruby gems on a Linux machine. This project helps you practice identifying the difference between a Ruby runtime, development headers, and build tools. It mirrors a real situation where a server can run Ruby scripts but fails when gems need compilation.

Goal

Build a repeatable setup process that prepares a Linux server to install native Ruby gems successfully.

Requirements

  1. Check the installed Ruby version.
  2. Install the Ruby development package for the system.
  3. Install basic build tools such as gcc and make.
  4. Attempt to install the json gem.
  5. Verify the gem can be required from Ruby.
Take Quiz

Keep learning

Related questions

View more