G2
Developer Tools Azure

Gemstash on Ubuntu 24.04 on Azure User Guide

| Product: Gemstash 2.8 on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Gemstash 2.8 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Gemstash is a RubyGems server built by the RubyGems and Bundler team. It does two jobs on a single node: it is a pull through cache and mirror of rubygems.org, so bundle and gem install fetch public gems through one shared endpoint that caches every gem for the whole team, and it is a private gem repository for pushing and hosting your own gems.

The image installs the pinned Gemstash 2.8.2 gem under the Ubuntu 24.04 archive Ruby (3.2, security supported) and runs it under systemd. The Gemstash server binds to loopback only (127.0.0.1:9292); nginx is the sole network facing surface on port 80 and reverse proxies to it. Public gems are served from the mirror without authentication; pushing and yanking private gems is gated by API keys.

Security by design — no baked API key. Gemstash gates private gem push and yank with API keys created by gemstash authorize; fetching cached public gems needs no authentication. This image ships no API key at all. On the very first boot, before the port is reachable, a unique push API key is generated with openssl rand -hex 24, authorized, and written to /root/gemstash-credentials.txt (mode 0600, root only), and an unauthenticated private push is proven to be rejected with HTTP 401 before the instance is marked ready. The gem cache, private gems and SQLite database are created fresh per VM, so the captured image carries no cached gem, no private gem and no key.

What is included:

  • Gemstash 2.8.2 (MIT licensed), installed under the Ubuntu 24.04 archive Ruby (3.2), run under systemd as the unprivileged gemstash system user

  • A pull through mirror of rubygems.org and a private gem repository on one VM

  • The Gemstash server bound to loopback only (127.0.0.1:9292) — never directly network exposed

  • nginx on port 80 as the sole network facing surface, with client_max_body_size 0 for gem pushes

  • A per instance push API key generated on first boot and stored in /root/gemstash-credentials.txt (0600) — no baked key, no shared default

  • A SQLite backed store with the gem cache and private gems under /var/lib/gemstash, created fresh per VM

  • Ubuntu 24.04 LTS base with latest security patches applied at build time

  • Azure Linux Agent for seamless cloud integration and SSH key injection

  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region

  • Subscription to the Gemstash listing on Azure Marketplace

  • A machine with Ruby and Bundler installed to push private gems and to point bundle/gem at the mirror

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for a team mirror and private repository. Servers with many concurrent installs or a large cache should use Standard_D2s_v5 (2 vCPU, 8 GB RAM) or larger, and a larger OS disk for the cache.

Step 1: Deploy from the Azure Portal

Search Gemstash in Marketplace, select the cloudimg publisher, click Create. NSG rules: TCP 22 (admin) and TCP 80 (the gem server) from your client networks.

Step 2: Deploy from the Azure CLI

RG="gemstash-prod"; LOCATION="eastus"; VM_NAME="gemstash-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/gemstash/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name gemstash-vnet --address-prefix 10.100.0.0/16 --subnet-name gemstash-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name gemstash-nsg
az network nsg rule create -g "$RG" --nsg-name gemstash-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name gemstash-nsg --name allow-http --priority 110 \
  --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name gemstash-vnet --subnet gemstash-subnet --nsg gemstash-nsg --public-ip-sku Standard

Step 3: Connect via SSH and retrieve your API key

The per instance push API key is generated on the first boot and stored in a root only file. Connect over SSH and read it:

ssh azureuser@<public-ip>
sudo cat /root/gemstash-credentials.txt

The file contains the mirror URL, the private repository URL and the per instance API key, plus quick start commands. Store the key somewhere safe — it is unique to this VM and it is what authorizes pushing private gems.

Step 4: Verify the gemstash and nginx services

Confirm both services are active and that Gemstash is bound to loopback only. In the listener output, 127.0.0.1:9292 (Gemstash) is loopback only, while nginx listens publicly on :80:

systemctl status gemstash nginx --no-pager
gemstash version
ss -tln | grep -E ':9292|:80 '

gemstash.service and nginx.service both active (running), gemstash reporting version 2.8.2, and ss showing Gemstash bound to 127.0.0.1:9292 loopback only with nginx public on :80

Step 5: Check the health endpoint

The /healthz endpoint is served by nginx without authentication (ideal for load balancer and Azure health probes) and returns HTTP 200:

curl -o /dev/null -w 'healthz: HTTP %{http_code}\n' http://127.0.0.1/healthz

Step 6: Use Gemstash as a pull through mirror for public gems

Gemstash caches public gems from rubygems.org and serves them from the mirror at the root URL. Fetching public gems needs no authentication. From the VM you can confirm the pull through works by fetching a public gem through Gemstash — it downloads from rubygems.org the first time and caches it for everyone after:

gem fetch --clear-sources --source http://127.0.0.1/ rake

gem fetch of the public gem rake through Gemstash downloading rake 13.4.2 and caching it, with the gemstash config.yml showing the SQLite adapter, the loopback bind and the rubygems.org upstream

On your developer machines or CI, point Bundler at the mirror so every bundle install goes through Gemstash. Replace <public-ip> with your VM's public IP or DNS name:

bundle config mirror.https://rubygems.org http://<public-ip>

From then on, bundle install fetches public gems through your Gemstash server, cached and shared across the team.

Step 7: Push and host private gems

Private gems are pushed to the /private path and require the per instance API key — an unauthenticated push, or a push with the wrong key, is rejected with HTTP 401. The screenshot below shows the full proof: a push with no key returns 401, a push with a wrong key returns 401, a push with the per instance key returns 200, and the private gem is then fetchable.

Pushing a private gem to Gemstash: a push with no API key returns HTTP 401, a push with a wrong API key returns HTTP 401, a push with the per instance API key returns HTTP 200, and fetching the private gem back returns HTTP 200 — no baked key is accepted

To push one of your own gems, add your per instance API key to Rubygems' credentials, then push to the /private host. Replace <public-ip> and <GEMSTASH_API_KEY> with your VM's IP and the key from Step 3:

mkdir -p ~/.gem && chmod 0700 ~/.gem
echo -e "---\n:cloudimg: <GEMSTASH_API_KEY>" >> ~/.gem/credentials
chmod 0600 ~/.gem/credentials
gem push --key cloudimg --host http://<public-ip>/private my-gem-0.1.0.gem

Install a private gem in a Gemfile by wrapping it in a source block that points at /private, and let Gemstash serve everything else from the mirror:

source "http://<public-ip>"
gem "rake"

source "http://<public-ip>/private" do
  gem "my-gem"
end

Step 8: How Gemstash is wired and secured

The Gemstash configuration at /etc/gemstash/config.yml binds the server to loopback only, stores its data under /var/lib/gemstash with the SQLite adapter, and points the mirror upstream at rubygems.org. The per instance API key lives in the root only credentials file, and gemstash authorize --list shows exactly one key on a fresh VM:

grep -E ':bind|:base_path|:db_adapter|:rubygems_url|:protected_fetch' /etc/gemstash/config.yml
sudo stat -c '%n %a %U:%G' /root/gemstash-credentials.txt

The gemstash-credentials.txt file at mode 0600 root:root with the per instance API key masked, the config.yml showing the loopback bind and SQLite adapter, and gemstash authorize --list showing a single per VM key with push, yank and fetch permissions

Step 9: Use your own domain and TLS (production)

Gemstash is served over plain HTTP on port 80 for convenience. For production, front it with your own DNS name and a CA signed certificate:

  • Point a DNS record (for example gems.example.com) at the VM public IP.

  • Add a TLS server block to nginx (for example with a Let's Encrypt certificate via certbot, or your internal CA), proxying to http://127.0.0.1:9292, then run sudo nginx -t && sudo systemctl reload nginx.

  • Clients then use https://gems.example.com for both the mirror and /private.

Step 10: Protect private fetching and scale the database

  • Protected fetching. By default, private gems can be fetched without a key. To require an API key with the fetch permission for private gem downloads too, run sudo gemstash setup and enable protected fetching, then restart Gemstash. Clients pass the key as the HTTP Basic auth username on the /private source.

  • PostgreSQL for durability. For larger or highly durable deployments, switch the store from SQLite to an on box PostgreSQL by setting :db_adapter: postgres and the connection options in /etc/gemstash/config.yml, then restart Gemstash. SQLite is the self contained default and needs no database password.

Step 11: Server components

Component Version / Detail
Gemstash 2.8.2 (MIT), by the RubyGems and Bundler team
Ruby Ubuntu 24.04 archive Ruby 3.2 (security supported)
Server binding 127.0.0.1:9292 (loopback only)
Front proxy nginx (:80), client_max_body_size 0, /healthz 200
Store SQLite adapter, base path /var/lib/gemstash (gem cache + private gems + DB)
Credential per instance push API key, generated first boot, /root/gemstash-credentials.txt (0600)
Operating system Ubuntu 24.04 LTS (patched at build)
License MIT (Gemstash)

Step 12: Managing the Gemstash service

sudo systemctl status gemstash
sudo systemctl restart gemstash
sudo journalctl -u gemstash -f
sudo systemctl reload nginx

The gem cache, private gems and SQLite database live under /var/lib/gemstash and persist across service restarts and VM reboots. To create more API keys or scope permissions, run sudo gemstash authorize push yank --config-file /etc/gemstash/config.yml; to rotate or remove a key, use sudo gemstash authorize --remove --key <key> --config-file /etc/gemstash/config.yml.

Step 13: Security recommendations

  • Restrict the NSG. Allow TCP 80 (and 22 for admin) only from the client networks that need the mirror and the private repository. Do not expose Gemstash to the public internet unless you intend to.

  • Front with TLS (Step 9) for production so gem traffic and API keys are encrypted in transit.

  • Enable protected fetching (Step 10) if your private gems must not be downloadable without a key.

  • Rotate the API key. Remove the per instance key and authorize a new one with gemstash authorize if it is ever exposed.

  • Keep the OS patched. Unattended security upgrades remain enabled on the running VM.

  • Back up /var/lib/gemstash to preserve your private gems and cache.

Step 14: Support and Licensing

Gemstash is free and open source software built by the RubyGems and Bundler team, distributed under the MIT License. This cloudimg image bundles the unmodified upstream gem. cloudimg provides the packaging, hardening, per instance API key automation and 24/7 support with a guaranteed 24 hour response SLA. This image is not affiliated with, endorsed by, or sponsored by the RubyGems project; the Gemstash name is used only to identify the software shipped in this image.

Deploy on Azure

Find Gemstash on Ubuntu 24.04 on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.

Need Help?

Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.