Running a Private GemServer inside the Firewall
rubygems.org has made it so easy to publish a gem for the world to use but what do you do when your gem is proprietary and you only want to publish it within your company?
This is something I’ve just been through at my company and thought I’d share the steps I went through. We need to
- Setup an inside-the-firewall gem server
- Configure our gems to deploy to it
- Configure our apps to use it
Setup an inside-the-firewall gem server
The first thing you have to decide is what gemserver to use. Rubygems.org has a helpful page called running your own gemserver that basically lists 3 choices in a goldilocks situation.
too small - gem server is a command built into rubygems
This works but you need to log onto the server to install a new gem and it serves all gems on the system not just your proprietary ones
too big - rubygems.org is open source so we could deploy it on our own server
This seems pretty complex to setup and even they tell you to “consider checking out Geminabox”
just right - gem in a box is a simple sinatra app to allow you to host your own in-house gems
This is easy to setup, has a web interface and supports a command line to remotely publish new gems.
geminabox is what I decided to go with.
The readme on github describes the server setup for geminabox and it just worked. The only thing to keep in mind is that you cannot use bundler as then you will only serve the gems in the bundle instead of the gems you publish. I spent some time adding bundler before realizing that was a bad idea and backing it out.
Once geminabox is up and running you can view your gems at your internal url and you’ll see the gem server homepage showing you it has no gems.
The easiest thing is to add a new gem by clicking “Upload Another Gem” and selecting a
.gem file from your hard drive
diagnostics-0.0.1.gem in the image below).
Once you click
uppload you should see your gem on the page.
At this point we could start using this gem server in our apps but before we talk about that let’s automate the manual process we just went through to add a gem.
Configure our gems to deploy to the gem server
I’ve been using bundler to create my gems with the
bundle gem command and one of the features that gives you is a set of nice rake tasks.
Check out the New Gem with Bundler Railscast to learn how it works.
Let’s look at the tasks we’ve got.
rake build and
rake install do their work locally but
rake release is what you call when you’re done and ready to release your gem into the wild.
This task will push your changes to github, create a git tag,
build your gem package and deploy it to http://rubygems.org.
We need to do something to change that last part so it deploys to our private gem server instead of rubygems.org.
Let’s spend some time looking into bundler to figure out how
rake release works.
The magic all happens inside a file
* It defines a :release rake task
* Which calls release_gem
* Which calls [rubygem_push] (https://github.com/carlhuda/bundler/blob/1-0-stable/lib/bundler/gem_helper.rb#L72-79)
* Finally this will call
gem push pkg/my_awesome_gem-0.0.1.gem which pushes to http://rubygems.org. We’ve found the behavior we need to change.
geminabox adds a custom rubygems command called
inabox so you can deploy a gem with the command
gem inabox pkg/my-awesome-gem-1.0.gem.
Unfortunately bundler does not seem to have a convenient way to change this so we’re going to monkey patch bundler
method to use the geminabox command instead. (please let me know if you have a better idea)
We’ll add our monkey patch to our
Rakefile since its called by a rake command.
You can see this will call
gem inabox ... so we also need to add
geminabox to our gem’s bundle. We do this in the
.gemspec as a development dependency
Now when we call
rake release it will push the gem to our private server instead of the public one. Let’s see:
Now when we go to the gem server site, we can see our new awesome gem in the list
The gem is there an you can use install it with a command like
gem install my_awesome_gem --source http://gems.intranet.mycompany.com
Using your Gem Server from an application
We’ve just seen how we can use the
source option to tell rubygems where to look when installing our gem by hand,
but in a modern application we all use
bundler and a
Gemfile to manage our gems so
how do we tell bundler to user our private gemserver for our private gems?
Its super simple, you just need to add a
source to the top of your
Now when we run
bundle it looks in our private gem server as well as the public rubygems.org.
Now that that you’ve got my_awesoem_gem you’re ready to add awesomeness to your app.