<?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>Forem: Martin Voldřich</title>
    <description>The latest articles on Forem by Martin Voldřich (@rbas).</description>
    <link>https://forem.com/rbas</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%2F3791793%2F9b8be844-496d-4c61-b03e-638267be9d7e.png</url>
      <title>Forem: Martin Voldřich</title>
      <link>https://forem.com/rbas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rbas"/>
    <language>en</language>
    <item>
      <title>I got tired of localhost:3000, so I built a local dev proxy with custom domains and trusted HTTPS</title>
      <dc:creator>Martin Voldřich</dc:creator>
      <pubDate>Wed, 25 Feb 2026 13:45:51 +0000</pubDate>
      <link>https://forem.com/rbas/i-got-tired-of-localhost3000-so-i-built-a-local-dev-proxy-with-custom-domains-and-trusted-https-1dj6</link>
      <guid>https://forem.com/rbas/i-got-tired-of-localhost3000-so-i-built-a-local-dev-proxy-with-custom-domains-and-trusted-https-1dj6</guid>
      <description>&lt;p&gt;Every web developer knows the routine. You start your frontend on port 3000,&lt;br&gt;
your API on 3001, maybe an admin dashboard on 8080. Open a browser tab, stare&lt;br&gt;
at it... which port was which again?&lt;/p&gt;

&lt;p&gt;It gets worse when you juggle multiple projects. Two apps both want port 3000.&lt;br&gt;
You're switching between client projects and can't remember if the e-commerce&lt;br&gt;
site was :3000 or :3001 today. And your bookmarks bar is full of&lt;br&gt;
&lt;code&gt;localhost:something&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I decided to fix this for myself and ended up building&lt;br&gt;
&lt;a href="https://github.com/rbas/roxy" rel="noopener noreferrer"&gt;Roxy&lt;/a&gt; — a local development proxy that&lt;br&gt;
replaces localhost ports with custom &lt;code&gt;.roxy&lt;/code&gt; domains and browser-trusted HTTPS.&lt;/p&gt;
&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;p&gt;Instead of &lt;code&gt;http://localhost:3000&lt;/code&gt;, you get &lt;code&gt;https://myapp.roxy&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;roxy register shop.roxy &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/=3000"&lt;/span&gt; &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/api=3001"&lt;/span&gt;
roxy register blog.roxy &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/=4000"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;roxy start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Open &lt;code&gt;https://shop.roxy&lt;/code&gt; in your browser — green lock, no&lt;br&gt;
certificate warnings, no config files. &lt;code&gt;https://blog.roxy&lt;/code&gt; is a completely&lt;br&gt;
separate project running alongside it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pvbsyt5pa2bruo91anx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pvbsyt5pa2bruo91anx.gif" alt="Roxy demo" width="800" height="647"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;Roxy is a single binary that bundles three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A DNS server&lt;/strong&gt; — resolves all &lt;code&gt;.roxy&lt;/code&gt; domains to &lt;code&gt;127.0.0.1&lt;/code&gt;. No need to
edit &lt;code&gt;/etc/hosts&lt;/code&gt; or install dnsmasq.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A certificate authority&lt;/strong&gt; — generates trusted HTTPS certificates on the
fly. The root CA gets installed into your system trust store during
&lt;code&gt;roxy install&lt;/code&gt;, so browsers trust everything automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A reverse proxy&lt;/strong&gt; — routes incoming requests to your local services based
on the domain and path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One-time setup takes about 10 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install (macOS via Homebrew, or build from source on Linux)&lt;/span&gt;
brew tap rbas/roxy &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;roxy

&lt;span class="c"&gt;# One-time setup — creates Root CA, configures DNS&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;roxy &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you just register domains and start the proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features I use every day
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Path-based routing&lt;/strong&gt; — run multiple services behind one domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;roxy register myapp.roxy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/=3000"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/api=3001"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/admin=8080"&lt;/span&gt;

&lt;span class="c"&gt;# https://myapp.roxy       → frontend&lt;/span&gt;
&lt;span class="c"&gt;# https://myapp.roxy/api   → API&lt;/span&gt;
&lt;span class="c"&gt;# https://myapp.roxy/admin → admin panel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Wildcard subdomains&lt;/strong&gt; — great for multi-tenant SaaS development:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;roxy register myapp.roxy &lt;span class="nt"&gt;--wildcard&lt;/span&gt; &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/=3000"&lt;/span&gt;

&lt;span class="c"&gt;# https://myapp.roxy            → main app&lt;/span&gt;
&lt;span class="c"&gt;# https://acme.myapp.roxy       → tenant "acme"&lt;/span&gt;
&lt;span class="c"&gt;# https://globex.myapp.roxy     → tenant "globex"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Static file serving&lt;/strong&gt; — point a route at a directory and get a built-in file&lt;br&gt;
browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;roxy register docs.roxy &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/=./build"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real-time traffic logs&lt;/strong&gt; — see every request flowing through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;roxy logs &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The tech
&lt;/h2&gt;

&lt;p&gt;I wrote Roxy in Rust. The whole thing is about 5k lines and compiles to a&lt;br&gt;
single binary with zero runtime dependencies. The main building blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/tokio-rs/axum" rel="noopener noreferrer"&gt;axum&lt;/a&gt; for the HTTP server and reverse
proxy&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/rustls/rustls" rel="noopener noreferrer"&gt;rustls&lt;/a&gt; for TLS (no OpenSSL dependency)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/rustls/rcgen" rel="noopener noreferrer"&gt;rcgen&lt;/a&gt; for certificate generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs on &lt;strong&gt;macOS&lt;/strong&gt; (Monterey+) and &lt;strong&gt;Linux&lt;/strong&gt; (Ubuntu 22.04+ / Debian 12+).&lt;br&gt;
The Linux support just landed in v0.5.0, which I shipped this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS&lt;/span&gt;
brew tap rbas/roxy &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;roxy

&lt;span class="c"&gt;# Or build from source (macOS or Linux)&lt;/span&gt;
git clone https://github.com/rbas/roxy.git
&lt;span class="nb"&gt;cd &lt;/span&gt;roxy &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Then&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;roxy &lt;span class="nb"&gt;install
sudo &lt;/span&gt;roxy register myapp.roxy &lt;span class="nt"&gt;--route&lt;/span&gt; &lt;span class="s2"&gt;"/=3000"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;roxy start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project is open source (MIT):&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/rbas/roxy" rel="noopener noreferrer"&gt;github.com/rbas/roxy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd love to hear how you handle local dev routing — do you just live with&lt;br&gt;
localhost ports, or have you found a setup that works? Let me know in the&lt;br&gt;
comments.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
