# Geminabox private gem hosting and Bundler setup

> Geminabox is a Rack application for publishing and serving private Ruby gems through a compact index compatible with Bundler. It fits organizations that need a small internal gem repository, but version 4.0 no longer proxies rubygems.org.

**geminabox/geminabox** — Really simple rubygem hosting

- Repository: https://github.com/geminabox/geminabox
- Website: https://rubygems.org/gems/geminabox
- Stars: 1,547 · Forks: 324
- Language: Ruby
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/geminabox-geminabox

## Geminabox's private gem repository boundary

Geminabox addresses the need to publish internal Ruby gems without sending every package through rubygems.org. It is intended for teams that want a controlled gem server for internal libraries, reusable application components, or packages that should remain on infrastructure they operate. Clients use the same gem publishing and Bundler workflows they use with the public RubyGems service, although Geminabox serves only the gems uploaded to it.

That boundary is central to version 4.0. Geminabox does not merge local packages with packages from rubygems.org. An application can declare rubygems.org as its normal source and configure the Geminabox host as a scoped source containing selected internal gems. Bundler then resolves each gem from exactly one declared source. This is useful when the same gem name exists on both services because it prevents the private name from resolving accidentally from the public repository.

Geminabox does not include a complete identity or authorization system. The README leaves authentication to the web server or Rack stack and points to `Rack::Auth::Basic` as one option. Public deployments therefore need an explicit security layer rather than relying on the presence of the gem host alone.

## Rack application, stored gems, and materialized compact index

The repository implements Geminabox as a Rack application exposed through `Geminabox::Server`. Stored gem files determine what the service publishes. Its web interface lists hosted gems and presents installation commands, while the RubyGems-compatible endpoints support normal package retrieval and publishing.

Dependency discovery uses the compact index API. According to the README, Geminabox serves `/versions`, `/info/GEMNAME`, and `/names`, which Bundler 1.12 and later can discover without special client configuration. The compact index is materialized under `data/compact_index/`. Geminabox updates it when a gem is added or removed. Deleting that directory or requesting `/reindex` is documented as safe because the index is rebuilt from the stored gems on the next request.

This design keeps most client configuration out of the installation process, but it creates an operational consequence after an upgrade. The first request to `/versions` may have to checksum every stored gem when rebuilding the index. The README recommends hitting `/versions` or `/reindex` immediately after upgrading an installation that contains many gems, rather than allowing the delay to appear during the first `bundle install`.

The web server can run through `rackup` or through deployment stacks such as Passenger, Puma, or Unicorn. Storage location is explicit through `Geminabox.data`, so operational work includes ensuring that the selected directory exists, remains writable by the application account, and is backed up according to the organization's storage policy.

## Installing Geminabox and creating the first scoped source

The README requires Ruby 3.0 or later and RubyGems 3.2.3 or later. It recommends Ruby 3.2 or later and the latest RubyGems release. Install Geminabox together with the Rack command and a Rack server:

```bash
gem install geminabox rackup webrick
```

The installation uses WEBICK for the example, but the README states that other Rack servers are supported. After the command completes, create a `config.ru` with the data directory, session middleware, protection middleware, and Rack application entry point:

```ruby
require "rubygems"
require "geminabox"

Geminabox.data = "/var/geminabox-data"

use Rack::Session::Pool, expire_after: 1000
use Rack::Protection

run Geminabox::Server
```

The comments in the README recommend `Rack::Protection` for a publicly reachable server. Its session setting is only an example. `Rack::Session::Pool` is not available for multiprocess servers such as Unicorn, and the README also notes that its internal `@pool` hash does not expire stored entries, which can cause a memory leak. Public or multiprocess deployments need a session implementation suited to that server model.

Start the development server with:

```bash
rackup
```

This launches the Rack application using the adjacent `config.ru`. For a first client use, point a Gemfile at both rubygems.org and the Geminabox host, placing only internal packages in the scoped block:

```ruby
source "https://rubygems.org"

source "https://gems.example.com" do
  gem "internal-widgets"
  gem "internal-tools"
end
```

Replace the example host with the deployed Geminabox URL. The repository confirms that Bundler discovers the compact index without additional client configuration. A client resolving that Gemfile should obtain public dependencies from rubygems.org and the listed private gems from Geminabox.

## Reverse proxy rules for compact index integrity

A normal nginx or Passenger deployment does not require special compact-index configuration according to the README. gzip can remain enabled because Bundler sends ranged requests without `Accept-Encoding`, and nginx does not compress 206 responses. The documented setup therefore preserves 304 revalidation and ranged tail appends.

Caching rules need more care. The README says not to cache `/versions`, `/info/*`, or `/names` at nginx or through a CDN. These files reference one another through checksums. A proxy cache can return a fresh copy of one file and a stale copy of another, after which Bundler reports checksum mismatches even though Bundler already performs its own client-side caching and revalidation.

Header rewriting also changes client behavior. Removing `ETag` disables 304 revalidation. Removing `Repr-Digest` or `Digest` prevents Bundler from appending partial responses, so it downloads the complete file again after each change. Middleboxes and custom middleware should therefore be checked against those headers rather than treating the compact index like an ordinary static directory.

These constraints make Geminabox less tolerant of indiscriminate proxy optimization than a static file host. An engineer setting it up needs control over cache policies and response headers, not merely a working TLS termination rule.

## Publishing overwrites and Bundler checksum failures

Geminabox can overwrite a stored gem with `gem inabox -o` when the server has the `allow_replace` option enabled. The operation changes the contents associated with an existing name and version, and Geminabox updates its compact index and advertised checksum.

Bundler protects clients from this after the version has been recorded in `Gemfile.lock`. Since Bundler 2.5, its `CHECKSUMS` section records gem checksums. If the server later advertises different bytes for the same name and version, Bundler stops with `Bundler::ChecksumMismatchError`. Server configuration cannot override that conflict because the mismatch is between the client's lockfile and the replacement package.

The README lists several client-side responses, including removing the gem's `CHECKSUMS` entry, deleting the lockfile and resolving again, or disabling local checksum validation with `bundle config set --local disable_checksum_validation true`. These are workarounds for an already affected client. The documented cleaner practice is to publish a new gem version instead of replacing bytes under an existing version.

This limitation makes overwrite support unsuitable for routine correction. It may be useful for a private package that no consumer has locked, but it transfers a supply-chain warning to every later resolver. The repository describes `-o` as a convenience rather than the normal publication path.

## Version 4.0 migration and repository maintenance

Geminabox 4.0 removes the old RubyGems proxy because it depended on the RubyGems.org Dependency API at `/api/v1/dependencies`, which was sunset on 2023-05-24. The README also states that combining remote and local gems in one namespace creates dependency-confusion risk and interferes with Bundler source pinning. Version 4.0 therefore requires clients to point public dependencies at rubygems.org and private dependencies at Geminabox through a scoped source block.

Upgraders must remove `Geminabox.rubygems_proxy` and the related settings `rubygems_proxy_merge_strategy`, `allow_remote_failure`, `ruby_gems_url`, and `bundler_ruby_gems_url`. The `RUBYGEMS_PROXY` and `RUBYGEMS_PROXY_MERGE_STRATEGY` environment variables receive the same treatment. Version 4.0 warns about and ignores these settings, and the README says the compatibility warnings will be removed in 5.0. A migration can therefore complete before every obsolete configuration key has been cleaned up, but leaving it in place obscures whether the intended architecture is actually configured.

For installations that need caching or mirroring of rubygems.org, the README names gemstash as the alternative. Gemstash addresses upstream RubyGems proxying and caching, while Geminabox 4.0 handles the private repository. Their separation avoids restoring the merged namespace that Geminabox removed.

The repository is not archived. Its last push was on 2026-10-15, and the listed releases include `v4.0.1`, `v3.1.1`, and `v4.0.0` in September 2026. The project uses the MIT license. That designation governs the stated licensing terms, but organizations should review the actual `MIT-LICENSE` and their distribution obligations for any separate legal review.

## Conclusion

Adopt Geminabox when a small internal gem repository and an unmodified Bundler client are the priority. Do not adopt it as a transparent rubygems.org cache or mixed public and private gem namespace. Before deployment, verify the persistence and ownership of `/var/geminabox-data`, configure authentication at the web server or Rack layer, test the scoped-source Gemfile from a separate client directory, and review the removed proxy settings before upgrading to 4.0.

## FAQ

### What Ruby version does Geminabox require?

The README requires Ruby 3.0 or later and recommends Ruby 3.2 or later. It also requires RubyGems 3.2.3 or later.

### Can Geminabox proxy rubygems.org in version 4.0?

No. The RubyGems proxy was removed in 4.0 after the upstream Dependency API was sunset and because mixed namespaces conflict with Bundler source pinning.

### Does Bundler need configuration to use the Geminabox compact index?

No. Bundler 1.12 and later detect the compact index automatically, so the Gemfile can use a scoped Geminabox source without additional client configuration documented by the README.

### Why does Bundler report a checksum error after a gem is overwritten?

Bundler stores checksums in `Gemfile.lock` and detects that the same gem version has changed on the server. Publishing a new version is the clean fix described by the README.

### How should authentication be added to Geminabox?

Geminabox leaves authentication to the web server or Rack stack. The README suggests `Rack::Auth::Basic` as one possible Rack-based approach.

## Sources

- [geminabox/geminabox on GitHub](https://github.com/geminabox/geminabox)
- [License: MIT](https://github.com/geminabox/geminabox/blob/master/LICENSE)
- [Project website](https://rubygems.org/gems/geminabox)
- [README](https://github.com/geminabox/geminabox/blob/master/README.md)
- [Releases](https://github.com/geminabox/geminabox/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/geminabox-geminabox
