Rails 8 Adds Thruster as the Default HTTP/2 Proxy Server

Rails 8 ships Thruster in the default Docker flow. Use it for simple, single-container apps. Keep Nginx when we need edge features.

Puma stays as the app server. Thruster runs in front of Puma and handles the common reverse-proxy duties.

What is Thruster?

Thruster is a lightweight, Go-based HTTP/2 proxy from 37signals. It runs alongside Puma and provides:

  • HTTP/2 support
  • Optional automatic TLS certificates with Let’s Encrypt
  • Basic HTTP caching for public assets
  • X-Sendfile support for efficient file serving
  • Gzip compression

Before

Before Rails 8, a simple production setup often looked like this:

  1. Puma as the application server
  2. Nginx or Apache as a reverse proxy
  3. Certbot or another TLS certificate flow
  4. Manual configuration for asset caching and compression

That is a fair setup for complex infrastructure. It is too much ceremony for a small Rails app that just needs to run from one container.

After

Rails 8 includes the thruster gem and starts the container through bin/thrust unless Thruster is skipped.

The generated Dockerfile now ends with:

# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]

With TLS_DOMAIN configured, the same container can terminate HTTPS too. Without it, Thruster runs in HTTP-only mode.

How Thruster works

Thruster wraps the Puma process, so we do not need a separate process manager inside the container.

Without Thruster:

bin/rails server

With Thruster:

bin/thrust bin/rails server

Thruster starts first, then launches Puma as a child process. When Puma stops, Thruster stops too.

Key features

HTTP/2 support

Thruster provides HTTP/2 out of the box. That gives us multiplexed connections and header compression without configuring another proxy.

Automatic TLS with Let’s Encrypt

To enable automatic TLS, set the TLS_DOMAIN environment variable:

TLS_DOMAIN=myapp.com bin/thrust bin/rails server

This needs port 80 to be reachable so Let’s Encrypt can complete the ACME challenge.

Thruster automatically:

  • Provisions SSL certificates from Let’s Encrypt
  • Renews certificates before they expire
  • Handles HTTPS termination

If TLS_DOMAIN is not set, Thruster does not provision certificates and runs in HTTP-only mode.

Asset caching

Thruster can cache public assets and serve them directly. This reduces load on the Rails application for static file requests.

X-Sendfile support

For serving large files, Thruster supports X-Sendfile. When Rails emits an X-Sendfile header, it can hand the file path to Thruster, and Thruster can stream the file instead of making Ruby do the work.

# config/environments/production.rb
config.action_dispatch.x_sendfile_header = "X-Sendfile"
class DownloadsController < ApplicationController
  def show
    send_file Rails.root.join("storage/manual.pdf")
  end
end

Gzip compression

Thruster automatically compresses responses, reducing bandwidth usage and improving page load times.

It also includes a default jitter for compressed responses to reduce BREACH-style information leaks.

Configuration

Thruster is designed to be zero config. Most features are enabled automatically with sensible defaults.

When we need to customize it, we use environment variables:

# Set the domain for SSL certificates
TLS_DOMAIN=myapp.com

# Set Puma's target port
TARGET_PORT=3000

# Set public ports
HTTP_PORT=80
HTTPS_PORT=443

# Tune the cache
CACHE_SIZE=67108864
MAX_CACHE_ITEM_SIZE=1048576

# Disable gzip compression
GZIP_COMPRESSION_ENABLED=false

Thruster also accepts these with a THRUSTER_ prefix. For example, THRUSTER_TLS_DOMAIN can be used instead of TLS_DOMAIN to avoid collisions with application environment variables.

Using Thruster in Docker

Rails 8 adds the thruster gem to the generated Gemfile:

# Add HTTP asset caching/compression and X-Sendfile acceleration to Puma
gem "thruster", require: false

It also generates bin/thrust and uses it from the Dockerfile:

EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]

Skipping Thruster

If we do not want Thruster in a new Rails 8 application, we can skip it during generation:

rails new myapp --skip-thruster

This creates the application without the thruster gem and uses a standard Puma CMD in the Dockerfile.

To remove Thruster from an existing Rails 8 application:

  1. Remove the gem from the Gemfile:
gem "thruster", require: false
  1. Remove bin/thrust.

  2. Update the Dockerfile CMD to use Rails directly:

# Before
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]

# After
EXPOSE 3000
CMD ["./bin/rails", "server"]
  1. Run bundle install to update the lockfile.

This is useful when we already have a reverse proxy like Nginx or a cloud load balancer (ALB, CloudFront) handling SSL termination, caching, and compression in front of the application.

When to use Thruster

Use Thruster when:

  • The app runs on one server or a small set of app containers.
  • We control port 80 and want Let’s Encrypt inside the container.
  • We want HTTP/2, asset caching, compression, and X-Sendfile without maintaining Nginx config.

Skip Thruster when:

  • A CDN or load balancer already handles TLS and static assets.
  • We need advanced routing, rewrites, WAF rules, or complex header manipulation.
  • We need centralized cache behavior at the edge.

Operational caveats

Thruster is a better default, not a full edge platform.

  • Automatic TLS needs port 80 reachable from the public internet for certificate provisioning.
  • The asset cache is local to the running process, so tune CACHE_SIZE for larger apps.
  • If scale requires shared cache behavior, keep that at the CDN or load balancer layer.

Thruster vs Nginx

Feature Thruster Nginx
Configuration No config file Requires config files
TLS management Automatic with TLS_DOMAIN Manual, Certbot, or platform-managed
HTTP/2 Built in Requires configuration
Asset Caching Automatic Requires configuration
Complexity Minimal Higher
Best fit Simple Rails deployments Complex edge and routing setups

Conclusion

Thruster simplifies Rails production deployments by covering the common reverse proxy tasks inside the default Rails Docker setup.

It is not a replacement for every Nginx setup. It is the better default for the common case: a Rails app, a container, Puma, and fewer moving parts.

References

Need expert help with Rails performance?

Saeloun is a Rails Foundation Contributing Member helping teams modernize, upgrade, scale, and maintain production Rails applications.

Our Expertise

  • Rails contributors
  • 500+ Technical Articles
  • Production Rails consulting
  • Performance Optimization

Services

  • Rails application development
  • Code Audits
  • Rails upgrades
  • Team Augmentation

Need help on your Ruby on Rails or React project?

Join Our Newsletter