Question
Fixing Ruby Gem Native Extension Errors: mkmf.rb Can't Find Header Files for Ruby
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:
extconf.rbmkmf.rbto generate aMakefilemaketo 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:
jsonnokogiripgmysql2ffi
Mental Model
Think of a native gem like a machine that must be assembled before use.
- The gem provides the machine parts.
extconf.rbchecks whether your system has the right tools.mkmf.rbwrites the assembly instructions.makebuilds the machine.ruby.his 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.
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
Step by Step Execution
Example flow
Suppose you run:
gem install json
Here is what happens step by step:
- RubyGems downloads the gem.
- RubyGems sees that the gem includes native extension code.
- It runs:
ruby extconf.rb
extconf.rbusesmkmf.rbto inspect your system.mkmf.rblooks for Ruby header files, includingruby.h.- If the headers are missing, it stops and prints:
mkmf.rb can't find header files for ruby
- Because the
Makefilecannot be generated, compilation never starts. - 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
pgrequires PostgreSQL client development libraries - Installing
nokogirimay require XML-related build dependencies - Installing
jsonmay require Ruby development headers
A common lesson is that gem install may need both:
- network access to download the gem
- local development tools to compile it
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-devpackage 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
Comparisons
Ruby runtime vs Ruby development package
| Item | What it provides | Needed to run Ruby scripts | Needed to compile native gems |
|---|---|---|---|
| Ruby runtime | Ruby interpreter | Yes | No |
| Ruby development package | Headers like ruby.h | No | Yes |
| Build tools | gcc, make | No | Yes |
Pure Ruby gems vs native extension gems
| Gem type | Needs compilation | Common failure reason |
|---|---|---|
| Pure Ruby gem |
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 environmentmkmf.rb— generates
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-devruby-develruby1.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.
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
- Check the installed Ruby version.
- Install the Ruby development package for the system.
- Install basic build tools such as
gccandmake. - Attempt to install the
jsongem. - Verify the gem can be required from Ruby.
Keep learning
Related questions
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.
Difference Between require and include in Ruby
Learn the difference between require and include in Ruby, when to load a file, and when to mix module methods into a class.
How to Add One Array to Another in Ruby Without Creating a Nested Array
Learn how to combine arrays in Ruby without getting nested arrays or nil values. Understand push, concat, +, and flatten clearly.