<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Simon Chiu</title>
    <description>The latest articles on DEV Community by Simon Chiu (@geetfun).</description>
    <link>https://dev.to/geetfun</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F436297%2F0c758174-304b-41d5-b654-0301270eefa8.jpg</url>
      <title>DEV Community: Simon Chiu</title>
      <link>https://dev.to/geetfun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geetfun"/>
    <language>en</language>
    <item>
      <title>Using Thruster web server for Ruby apps</title>
      <dc:creator>Simon Chiu</dc:creator>
      <pubDate>Sat, 19 Oct 2024 11:48:22 +0000</pubDate>
      <link>https://dev.to/geetfun/using-thruster-web-server-for-ruby-apps-3ao</link>
      <guid>https://dev.to/geetfun/using-thruster-web-server-for-ruby-apps-3ao</guid>
      <description>&lt;p&gt;Recently, I set up some deployment scripts for a Ruby app where I wanted the server to handle SSL termination.&lt;/p&gt;

&lt;p&gt;In the "old" days, I would set up Caddy with reverse proxy the app with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Caddyfile
yourdomain.com {
    reverse_proxy localhost:3000
    tls
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of this, I would usually run Caddy as one of the dependencies in a &lt;code&gt;docker-compose.yml&lt;/code&gt; file to make it easier to install and reinstall everything.&lt;/p&gt;

&lt;p&gt;Recently, Basecamp released a simple reverse proxy server that handles everything I would need for serving Ruby apps in a gem called &lt;strong&gt;&lt;a href="https://github.com/basecamp/thruster" rel="noopener noreferrer"&gt;Thruster&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As per the GitHub repo, here is what this server brings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP/2 support&lt;/li&gt;
&lt;li&gt;Automatic TLS certificate management with Let's Encrypt&lt;/li&gt;
&lt;li&gt;Basic HTTP caching of public assets&lt;/li&gt;
&lt;li&gt;X-Sendfile support and compression, to efficiently serve static files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For 99% of the use cases out there, this fits the requirements perfectly. And best of all, I could run this &lt;em&gt;in the same container as my Ruby app&lt;/em&gt;. This means I don't need a separate container to run Caddy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;The gem is stated as a "no configuration" software, and this is &lt;em&gt;almost&lt;/em&gt; true.&lt;/p&gt;

&lt;p&gt;In reality, you still need to (at the very least) specify to Thruster which domains you want it to request SSL certificates for.&lt;/p&gt;

&lt;p&gt;This is done via the environment variable &lt;code&gt;TLS_DOMAIN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The good thing about this is that it is possible to specify multiple domains, so Thruster can automatically request the correct Let's Encrypt certs for each of them.&lt;/p&gt;

&lt;p&gt;For instance, if my app is serving from domain1.com and domain2.com, I could just specify it as &lt;code&gt;TLD_DOMAIN=domain1.com,domain2.com&lt;/code&gt; and Thruster would pick this up just fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Thruster
&lt;/h2&gt;

&lt;p&gt;To run Thruster, all you need to do is prefix it with the command you usually use to run your Ruby app.&lt;/p&gt;

&lt;p&gt;For example, if you're on Rails, you'd normally type &lt;code&gt;bin/rails server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The modification for thruster would be &lt;code&gt;thrust bin/rails server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I feel this is &lt;em&gt;why&lt;/em&gt; I like Thruster so much. With Caddy, I needed to set up a reverse proxy (oftentimes with trial and error with that darn Caddyfile). Using Thruster, I was able to get things set up in less than 3-5 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;p&gt;There are many options for serving web requests from Ruby (and Rails) apps these days in production environment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can do a reverse proxy, such as with &lt;a href="https://nginx.org/en/" rel="noopener noreferrer"&gt;nginx&lt;/a&gt; or &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;You can use &lt;a href="https://github.com/basecamp/kamal" rel="noopener noreferrer"&gt;Kamal&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;Or you can just use Thruster and have &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; monitor the service itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think in most cases, options (1) and (2) makes the most sense if it's on servers you control.&lt;/p&gt;

&lt;p&gt;For (3), there &lt;em&gt;is&lt;/em&gt; a special use case: self hosted applications. In other words, Ruby apps that your customers run on their own infrastructure and where they're the ones installing the app.&lt;/p&gt;

&lt;p&gt;The difference between the three described options is that in cases (1) and (2), it is easy for the devops person to go in and reconfigure things easily. &lt;/p&gt;

&lt;p&gt;When providing a Docker image (likely the most often scenario) to a customer to self-host, there are a lot of things that can go wrong.&lt;/p&gt;

&lt;p&gt;The customer may not be familiar with managing their own server, for example. Or perhaps the customer does not want to fiddle around with reverse proxies to make things work.&lt;/p&gt;

&lt;p&gt;In these cases, it's easier to just hand over a Docker container where things "just work".&lt;/p&gt;

&lt;p&gt;I ran into this problem while developing my &lt;a href="https://sendbroadcast.net" rel="noopener noreferrer"&gt;self-hosted email marketing software&lt;/a&gt;, and luckily Thruster was available.&lt;/p&gt;

&lt;p&gt;As I packaged everything into containers anyway and provide a &lt;code&gt;docker-compose.yml&lt;/code&gt; file, this also dropped my container dependencies from 4 to 3, eliminating the need to run nginx or Caddy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thruster is a pretty good alternative for handling reverse proxies to your Ruby app.&lt;/p&gt;

&lt;p&gt;Its simple "no-configuration" option makes it work very well in many scenarios. &lt;/p&gt;

&lt;p&gt;For myself, when packaging Ruby apps that need to be run in environments I don't control (ie. self hosted apps on customers' machines), this is the way to go.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>go</category>
    </item>
  </channel>
</rss>
