<?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: Jayden Robbins</title>
    <description>The latest articles on DEV Community by Jayden Robbins (@darknautica).</description>
    <link>https://dev.to/darknautica</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%2F3875287%2F0a8c0911-a1e1-4f1f-8199-c681e0dad027.jpeg</url>
      <title>DEV Community: Jayden Robbins</title>
      <link>https://dev.to/darknautica</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/darknautica"/>
    <language>en</language>
    <item>
      <title>I built a free self-hosted alternative to Pusher</title>
      <dc:creator>Jayden Robbins</dc:creator>
      <pubDate>Sun, 12 Apr 2026 17:44:18 +0000</pubDate>
      <link>https://dev.to/darknautica/i-built-a-free-self-hosted-alternative-to-pusher-1n92</link>
      <guid>https://dev.to/darknautica/i-built-a-free-self-hosted-alternative-to-pusher-1n92</guid>
      <description>&lt;p&gt;Every modern web app eventually needs real-time features. Live &lt;br&gt;
notifications, chat, presence indicators, collaborative editing. &lt;br&gt;
The moment you need it, every tutorial points you to Pusher.&lt;/p&gt;

&lt;p&gt;Pusher is great. It works, it's well documented, and the &lt;br&gt;
developer experience is solid. But the pricing hits hard once &lt;br&gt;
you have real traffic. 100 concurrent connections on the free &lt;br&gt;
tier. $49/month for 500. The bill scales faster than your app.&lt;/p&gt;

&lt;p&gt;The underlying technology — WebSockets — is open, well &lt;br&gt;
understood, and has been around for years. There was no good &lt;br&gt;
reason a polished self-hosted alternative didn't exist.&lt;/p&gt;

&lt;p&gt;So I built one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing Relay&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Relay is an open source, self-hostable WebSocket server written &lt;br&gt;
in Go. It gives you everything Pusher does at the cost of &lt;br&gt;
running a small server process on infrastructure you already own.&lt;/p&gt;

&lt;p&gt;The key design decision was full Pusher protocol compatibility. &lt;br&gt;
If you are already using Pusher, you can switch to Relay by &lt;br&gt;
changing one environment variable. No SDK changes, no refactoring, &lt;br&gt;
no migration script. Just point your app at your Relay server &lt;br&gt;
instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting started in 30 seconds&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 6001:6001 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;RELAY_APP_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-key &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;RELAY_APP_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-secret &lt;span class="se"&gt;\&lt;/span&gt;
  darknautica/relay:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the entire server setup. It starts on port 6001, &lt;br&gt;
serves a live dashboard at /dashboard, and is ready to &lt;br&gt;
accept WebSocket connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connecting from JavaScript&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Relay&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@relayhq/relay-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;relay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Relay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-server.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;relay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-notification&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Publishing from Laravel&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require relayhq/relay-php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config/broadcasting.php&lt;/span&gt;
&lt;span class="s1"&gt;'default'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'relay'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s1"&gt;'connections'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'relay'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'driver'&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'relay'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'host'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'RELAY_HOST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'127.0.0.1'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'port'&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'RELAY_PORT'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6001&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'key'&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'RELAY_APP_KEY'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'secret'&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'RELAY_APP_SECRET'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then your existing broadcast events just work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderShipped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it supports&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public, private, and presence channels&lt;/li&gt;
&lt;li&gt;HMAC authentication for private and presence channels&lt;/li&gt;
&lt;li&gt;HTTP publish API for backend event publishing&lt;/li&gt;
&lt;li&gt;Built-in web dashboard with live connection stats and event log&lt;/li&gt;
&lt;li&gt;Channel history and replay for clients that reconnect&lt;/li&gt;
&lt;li&gt;Webhooks with HMAC-signed payloads&lt;/li&gt;
&lt;li&gt;Multi-app support via apps.json&lt;/li&gt;
&lt;li&gt;Rate limiting and graceful shutdown&lt;/li&gt;
&lt;li&gt;Official SDKs for Laravel, Node.js, Rails, and Django&lt;/li&gt;
&lt;li&gt;Single binary — no runtime, no JVM, no Node required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The comparison that matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pusher free tier gives you 100 concurrent connections and &lt;br&gt;
200k messages per day. Relay gives you unlimited everything &lt;br&gt;
for the cost of a $5/month VPS.&lt;/p&gt;

&lt;p&gt;For a startup with 300 concurrent users, that is the &lt;br&gt;
difference between $0 and $49/month. Over a year that is &lt;br&gt;
$588 — more than the server costs for the whole year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project is MIT licensed and lives on GitHub. Pre-built &lt;br&gt;
binaries for Windows, Mac, and Linux are available on the &lt;br&gt;
releases page. A Docker image is published to Docker Hub.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/DarkNautica/Relay" rel="noopener noreferrer"&gt;https://github.com/DarkNautica/Relay&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://darknautica.github.io/Relay" rel="noopener noreferrer"&gt;https://darknautica.github.io/Relay&lt;/a&gt;&lt;br&gt;
Docker: darknautica/relay&lt;/p&gt;

&lt;p&gt;Would love feedback from anyone who has dealt with the &lt;br&gt;
Pusher pricing wall. Happy to answer questions about the &lt;br&gt;
Go architecture or the protocol implementation.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>laravel</category>
      <category>go</category>
    </item>
  </channel>
</rss>
