<?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: Alex Bouma</title>
    <description>The latest articles on DEV Community by Alex Bouma (@stayallive).</description>
    <link>https://dev.to/stayallive</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%2F113683%2Fa91401f5-b0a3-417d-a962-adf87b495220.jpg</url>
      <title>DEV Community: Alex Bouma</title>
      <link>https://dev.to/stayallive</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stayallive"/>
    <language>en</language>
    <item>
      <title>Setup Sentry Relay on Ubuntu</title>
      <dc:creator>Alex Bouma</dc:creator>
      <pubDate>Tue, 29 Aug 2023 08:00:00 +0000</pubDate>
      <link>https://dev.to/stayallive/setup-sentry-relay-on-ubuntu-41i1</link>
      <guid>https://dev.to/stayallive/setup-sentry-relay-on-ubuntu-41i1</guid>
      <description>&lt;p&gt;Sentry offers &lt;a href="https://docs.sentry.io/product/relay/"&gt;Relay&lt;/a&gt;, it's a proxy or relay that sits between your application and Sentry and can be used to filter events, add additional information, and more.&lt;br&gt;
In it's simplest form it can be used to relay events to Sentry (which is why it's called that 😉).&lt;/p&gt;

&lt;p&gt;There are a few key benefits to me that make Relay a great addition to your Sentry setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: Since you can deploy Relay close to your application (usually on the same host), you can send events to Sentry almost instantly without much networking overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt;: Relay will queue events when the Sentry instance is unreachable and tries to send them when Sentry is reachable again but while Sentry is down your application can continue to send events to Relay without any issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially for PHP applications Relay is a must-have since PHP is single threaded so every ms spent waiting for Sentry to respond is a ms your application can't do anything else and when Sentry is down or slow your application could be slow as well. &lt;br&gt;
The PHP SDK (of which I am a maintainer) tries to do as much as it can to minimize the impact of sending events to Sentry but it can only do so much and Relay solves the problem. See also &lt;a href="https://docs.sentry.io/platforms/php/performance/#improve-response-time"&gt;Improve Response Time&lt;/a&gt; from the PHP/Laravel/Symfony docs.&lt;/p&gt;

&lt;p&gt;There are 3 operating &lt;a href="https://docs.sentry.io/product/relay/modes/"&gt;modes for Relay&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;managed&lt;/code&gt; (only available on Business and Enterprise plans or self-hosted): Relay will request project settings from Sentry, so it can be configured from the UI.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;static&lt;/code&gt;: Relay is configured with specific &lt;a href="https://docs.sentry.io/product/sentry-basics/dsn-explainer/"&gt;DSN&lt;/a&gt;s it will allow, and allow accepts events for those projects.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy&lt;/code&gt;: Relay will proxy requests to Sentry, and will forward any event you sent to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will focus on the &lt;code&gt;proxy&lt;/code&gt; mode in this guide since it's the easiest to setup but apart from the specific configuration the setup is the same for all modes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: I am assuming a few things in this guide. That the reader knows how to use SSH and can perform basic command line actions. It is also assumed you are installing Relay on a Ubuntu server with &lt;code&gt;systemd&lt;/code&gt; (the guide was tested on Ubuntu 18.04/20.04/22.04).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you'd rather follow the official guide, you can find it &lt;a href="https://docs.sentry.io/product/relay/getting-started/"&gt;here&lt;/a&gt;, I will focus on running a binary with &lt;code&gt;systemd&lt;/code&gt; but there is also a Docker option in the official &lt;a href="https://docs.sentry.io/product/relay/getting-started/"&gt;Getting Started&lt;/a&gt; guide.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you are using &lt;a href="https://ploi.io/?referrer=BwZowvI55rM5y9ZVqjdB"&gt;Ploi&lt;/a&gt; to manage your servers you can use &lt;a href="https://ploi.io/panel/marketplace/305-sentry-relay?referrer=BwZowvI55rM5y9ZVqjdB"&gt;this marketplace script&lt;/a&gt; that performs the steps outlined below.&lt;br&gt;
However I highly recommend you read through this guide so you know what is happening and how to update Relay in the future.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing Relay
&lt;/h2&gt;

&lt;p&gt;Start by SSH'ing into your server and switching to the root user using &lt;code&gt;sudo su&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now the fun begins, starting with downloading the latest Relay binary from the &lt;a href="https://github.com/getsentry/relay/releases"&gt;Sentry Relay releases page&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: At the time of writing the latest release is &lt;code&gt;23.8.0&lt;/code&gt;, but you should check the &lt;a href="https://github.com/getsentry/relay/releases"&gt;release page&lt;/a&gt; to see if there is a newer version.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You want to download the &lt;code&gt;relay-Linux-x86_64&lt;/code&gt; release asset since that is the binary for Linux, at the time of writing there is no ARM binary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-O&lt;/span&gt; sentry-relay https://github.com/getsentry/relay/releases/download/23.8.0/relay-Linux-x86_64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we want to make the binary executable by setting the appropriate permissions:&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;chmod&lt;/span&gt; +x sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can move the binary to &lt;code&gt;/usr/local/bin&lt;/code&gt; so it's available globally:&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;mv &lt;/span&gt;sentry-relay /usr/local/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring Relay
&lt;/h2&gt;

&lt;p&gt;We downloaded the binary and made it available globally, now we need to configure Relay so it knows how to connect to Sentry and what to do with the events it receives.&lt;/p&gt;

&lt;p&gt;Start by creating a folder the configuration file, and use &lt;code&gt;sentry-relay&lt;/code&gt; to generate the &lt;code&gt;config.yml&lt;/code&gt;. This YAML file contains the configuration for Relay and if you need to edit it later you can find it at: &lt;code&gt;/etc/sentry-relay/config.yml&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;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/sentry-relay
sentry-relay config init &lt;span class="nt"&gt;-c&lt;/span&gt; /etc/sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will ask a few questions on how to setup Relay, you can find the answers below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Q: Do you want to create a new config?
A: Yes, create custom config

Q: How should this relay operate?
A: Proxy for all events

Q: upstream
A: https://sentry.io/

Q: listen interface
A: 127.0.0.1

Q: listen port
A: 3000

Q: do you want listen to TLS
A: no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: If you run a self-hosted instance replace the upstream answer with the hostname of your self-hosted instance.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setup &lt;code&gt;systemd&lt;/code&gt; service
&lt;/h2&gt;

&lt;p&gt;We downloaded the binary, made it executable, and created a configuration file. We are almost done!&lt;/p&gt;

&lt;p&gt;Now we need to setup &lt;code&gt;systemd&lt;/code&gt; so Relay will start on boot and can be managed via &lt;code&gt;systemd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We first need to create a user for Relay to run as, this is a security measure so Relay can't access any files it shouldn't be able to access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;useradd &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /bin/false sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This new user needs to be the owner of the configuration file we created earlier:&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;chown&lt;/span&gt; &lt;span class="nt"&gt;-Rf&lt;/span&gt; sentry-relay:sentry-relay /etc/sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to create a &lt;code&gt;systemd&lt;/code&gt; service file for Relay, this will tell &lt;code&gt;systemd&lt;/code&gt; how to start Relay and what user to run it as.&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;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt; /etc/systemd/system/sentry-relay.service
[Unit]
Description=Sentry Relay
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=3
User=sentry-relay
ExecStart=/usr/local/bin/sentry-relay run --config /etc/sentry-relay

[Install]
WantedBy=multi-user.target
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the &lt;code&gt;systemd&lt;/code&gt; service file we need to reload &lt;code&gt;systemd&lt;/code&gt; so it knows about the new service file and then enable the service so it will start on boot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl daemon-reload
systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl start sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And check the status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sending events to Relay
&lt;/h2&gt;

&lt;p&gt;The last part is updating the DSN in your application to send events to Relay instead of Sentry directly.&lt;/p&gt;

&lt;p&gt;Your DSN looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;https&lt;/strong&gt;://12345abcdef10111213141516171819@&lt;strong&gt;o1.ingest.sentry.io&lt;/strong&gt;/2345&lt;/p&gt;

&lt;p&gt;To send events to Relay we need to update the DSN to look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;http&lt;/strong&gt;://12345abcdef10111213141516171819@&lt;strong&gt;127.0.0.1:3000&lt;/strong&gt;/2345&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: We changed the protocol from &lt;code&gt;https&lt;/code&gt; to &lt;code&gt;http&lt;/code&gt; and the hostname from &lt;code&gt;o1.ingest.sentry.io&lt;/code&gt; to &lt;code&gt;localhost:3000&lt;/code&gt;. If you used different listen interface or port when creating the configuration make sure to re-use those here!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that Relay is running and we have our updated DSN we can send events to it, let's use &lt;code&gt;sentry-cli&lt;/code&gt; to do that (&lt;a href="https://docs.sentry.io/product/cli/installation/"&gt;installation instructions&lt;/a&gt;):&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;export &lt;/span&gt;&lt;span class="nv"&gt;SENTRY_DSN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'http://12345abcdef10111213141516171819@127.0.0.1:3000/2345'&lt;/span&gt;
sentry-cli send-event &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'A test event using Relay'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything went well you should see a new event in your Sentry project!&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating Relay
&lt;/h2&gt;

&lt;p&gt;Updating Relay is as simple as downloading the latest binary and replacing the old one, you can do this with the following commands:&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;# Download the latest binary (replace the version with the latest one)&lt;/span&gt;
wget &lt;span class="nt"&gt;-O&lt;/span&gt; sentry-relay https://github.com/getsentry/relay/releases/download/23.8.0/relay-Linux-x86_64

&lt;span class="c"&gt;# Make the binary executable&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x sentry-relay

&lt;span class="c"&gt;# Move the binary to /usr/local/bin&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;sentry-relay /usr/local/bin

&lt;span class="c"&gt;# Restart the Sentry Relay service&lt;/span&gt;
systemctl restart sentry-relay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>sentry</category>
      <category>ubuntu</category>
      <category>guide</category>
    </item>
    <item>
      <title>Laravel authenticated user ID in NGINX access log</title>
      <dc:creator>Alex Bouma</dc:creator>
      <pubDate>Mon, 09 Aug 2021 14:00:00 +0000</pubDate>
      <link>https://dev.to/stayallive/laravel-authenticated-user-id-in-nginx-access-log-2n78</link>
      <guid>https://dev.to/stayallive/laravel-authenticated-user-id-in-nginx-access-log-2n78</guid>
      <description>&lt;p&gt;For debugging and/or easy searching it's handy to have the user ID in the &lt;a href="https://nginx.org/"&gt;NGINX&lt;/a&gt; access logs so you can quickly find logs for a specific user.&lt;/p&gt;

&lt;p&gt;There are 2 parts to achieving this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the user ID as a response header to our Laravel app using a middleware&lt;/li&gt;
&lt;li&gt;Add the user ID as part of the NGINX log format and use that log format for the access logs&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Adding the user ID as a response header
&lt;/h2&gt;

&lt;p&gt;It makes the most sense to use a middleware for this purpose and we can make it really simple thanks to Laravel and PHP 8 syntax.&lt;/p&gt;

&lt;p&gt;Create the &lt;code&gt;app/Http/Middleware/AppendUserIdToResponse.php&lt;/code&gt; file:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Closure&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppendUserIdToResponse&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cd"&gt;/** @var \Symfony\Component\HttpFoundation\Response $response */&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'x-user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&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;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: I'm taking &lt;code&gt;$request-&amp;gt;user()?-&amp;gt;id&lt;/code&gt; here but nothing is stopping you from using &lt;code&gt;$request-&amp;gt;user()?-&amp;gt;username&lt;/code&gt; if that makes more sense for you.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We always add a header but if the user is not logged in we default to a &lt;code&gt;-&lt;/code&gt; which NGINX defaults to when the header is not set at all.&lt;/p&gt;

&lt;p&gt;Next we are going to register this new middleware in the &lt;code&gt;app/Http/Kernel.php&lt;/code&gt; in the &lt;code&gt;$middleware&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
&lt;span class="gi"&gt;+       \App\Http\Middleware\AppendUserIdToResponse::class,
&lt;/span&gt;    ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: We are adding it to the global middleware stack to make sure it runs for every request instead of needing to register it per route.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is it for the Laravel side (don't forget to deploy)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the user ID to the NGINX log format
&lt;/h2&gt;

&lt;p&gt;This part is a bit more "custom" and depends on how you have set up your NGINX and log formats, but let's give it a shot!&lt;/p&gt;

&lt;p&gt;Custom log formats can be defined in &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt; (within the &lt;code&gt;http {}&lt;/code&gt; block) and could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;log_format&lt;/span&gt; &lt;span class="s"&gt;main_ext&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="nv"&gt;$remote_addr&lt;/span&gt; &lt;span class="s"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$remote_user&lt;/span&gt; &lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$time_local&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="nv"&gt;$body_bytes_sent&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$http_referer&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$http_user_agent&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$http_x_forwarded_for&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;sn="&lt;/span&gt;&lt;span class="nv"&gt;$server_name&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'rt=&lt;/span&gt;&lt;span class="nv"&gt;$request_time&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'ua="&lt;/span&gt;&lt;span class="nv"&gt;$upstream_addr&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;us="&lt;/span&gt;&lt;span class="nv"&gt;$upstream_status&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'ut="&lt;/span&gt;&lt;span class="nv"&gt;$upstream_response_time&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;ul="&lt;/span&gt;&lt;span class="nv"&gt;$upstream_response_length&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'cs=&lt;/span&gt;&lt;span class="nv"&gt;$upstream_cache_status&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                    &lt;span class="s"&gt;'uid="&lt;/span&gt;&lt;span class="nv"&gt;$upstream_http_x_smls_user&lt;/span&gt;&lt;span class="s"&gt;"'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: this &lt;code&gt;log_format&lt;/code&gt; is the log format required by &lt;a href="https://amplify.nginx.com/"&gt;NGINX Amplify&lt;/a&gt; and used as an example.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To add our user ID to this we would do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" '
&lt;/span&gt;                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    '"$host" sn="$server_name" '
                    'rt=$request_time '
                    'ua="$upstream_addr" us="$upstream_status" '
                    'ut="$upstream_response_time" ul="$upstream_response_length" '
&lt;span class="gd"&gt;-                   'cs=$upstream_cache_status';
&lt;/span&gt;&lt;span class="gi"&gt;+                   'cs=$upstream_cache_status '
+                   'uid="$upstream_http_x_user"';
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the added &lt;code&gt;uid="$upstream_http_x_user"&lt;/code&gt; at the end, this will render as &lt;code&gt;uid="1"&lt;/code&gt; if user &lt;code&gt;1&lt;/code&gt; is logged in or &lt;code&gt;uid="-"&lt;/code&gt; if no user is logged in.&lt;/p&gt;

&lt;p&gt;It's possible you do not have a custom &lt;code&gt;log_format&lt;/code&gt; then your are using the default &lt;code&gt;combined&lt;/code&gt; format, add this log format which is &lt;code&gt;combined&lt;/code&gt; with the &lt;code&gt;uid&lt;/code&gt; field added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;log_format&lt;/span&gt; &lt;span class="s"&gt;combined_with_user_id&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="nv"&gt;$remote_addr&lt;/span&gt; &lt;span class="s"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$remote_user&lt;/span&gt; &lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$time_local&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                                 &lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="nv"&gt;$body_bytes_sent&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                                 &lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$http_referer&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$http_user_agent&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;
                                 &lt;span class="s"&gt;'uid="&lt;/span&gt;&lt;span class="nv"&gt;$upstream_http_x_user&lt;/span&gt;&lt;span class="s"&gt;"'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this we need to find the &lt;code&gt;access_log&lt;/code&gt; entries in our vhosts and make sure the correct log format is used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;...&lt;/span&gt;
    &lt;span class="s"&gt;access_log&lt;/span&gt; &lt;span class="n"&gt;/var/log/nginx/access.log&lt;/span&gt; &lt;span class="s"&gt;combined_with_user_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# or whatever you named your log format&lt;/span&gt;
    &lt;span class="kn"&gt;error_log&lt;/span&gt; &lt;span class="n"&gt;/var/log/nginx/error.log&lt;/span&gt; &lt;span class="s"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one last optional step, and that is to hide this header from the response. It should not be a security issue but there is no reason to have that header in the response so we are going to hide it:&lt;/p&gt;

&lt;p&gt;Locate the &lt;code&gt;fastcgi_pass&lt;/code&gt; section in your vhost config and add &lt;code&gt;fastcgi_hide_header x-user;&lt;/code&gt;, could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;/index.php&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;include&lt;/span&gt;                           &lt;span class="n"&gt;/etc/nginx/fastcgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;fastcgi_param&lt;/span&gt; &lt;span class="s"&gt;HTTPS&lt;/span&gt;               &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;fastcgi_param&lt;/span&gt; &lt;span class="s"&gt;HTTP_SCHEME&lt;/span&gt;         &lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;fastcgi_param&lt;/span&gt; &lt;span class="s"&gt;SCRIPT_FILENAME&lt;/span&gt;     &lt;span class="nv"&gt;$realpath_root$fastcgi_script_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt;                      &lt;span class="s"&gt;php80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;fastcgi_index&lt;/span&gt;                     &lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;fastcgi_hide_header&lt;/span&gt;               &lt;span class="s"&gt;x-user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;fastcgi_hide_header&lt;/span&gt;               &lt;span class="s"&gt;x-powered-by&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;fastcgi_split_path_info&lt;/span&gt;           &lt;span class="s"&gt;^(.+&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.php)(.*)&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;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;After you've made these changes NGINX should add &lt;code&gt;uid="1"&lt;/code&gt; if user &lt;code&gt;1&lt;/code&gt; is logged in or &lt;code&gt;uid="-"&lt;/code&gt; if no user is logged in to the access log entries.&lt;/p&gt;

&lt;p&gt;One caveat is that this only works for "dynamic" requests, requests that are handled by Laravel/PHP, so static files (like CSS / JS) will always have &lt;code&gt;uid="-"&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>nginx</category>
      <category>logging</category>
    </item>
    <item>
      <title>Laravel Websockets on Forge</title>
      <dc:creator>Alex Bouma</dc:creator>
      <pubDate>Tue, 15 Jan 2019 13:28:24 +0000</pubDate>
      <link>https://dev.to/stayallive/laravel-websockets-on-forge-4dkc</link>
      <guid>https://dev.to/stayallive/laravel-websockets-on-forge-4dkc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This article was last updated on 2021-05-15 and is written for Laravel 8.x and Laravel WebSockets 1.x and may or may not work for future Laravel or Laravel WebSockets versions.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It seems the documentation and or explanation on how to use &lt;a href="https://beyondco.de/docs/laravel-websockets/"&gt;Laravel WebSockets&lt;/a&gt; on Forge with SSL is not sufficient or clear enough.&lt;br&gt;
Some have asked for in-depth instructions on how to install Laravel WebSockets in Laravel and deploy it to Forge &lt;em&gt;with&lt;/em&gt; SSL (be it via Let's Encrypt or Cloudflare).&lt;/p&gt;

&lt;p&gt;In this post I'll try my best to explain how I have done it, but keep in mind I am using a new Laravel project which has no real code in it. &lt;br&gt;
But the gist should be the same for all projects and should help you get set up but be critical about the code you copy and make sure it applies to you. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: I am assuming a few things in this "guide". That the reader knows how to use composer, install Laravel (and packages) and how to setup a Forge server (with Daemons, firewall rules and a Let's Encrypt certificate).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With all the out of the way, let's jump in!&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up
&lt;/h2&gt;

&lt;p&gt;I am using the Laravel installer to install a new Laravel installation. The instructions on how to do that can be found in the official &lt;a href="https://laravel.com/docs/5.7/installation#installing-laravel"&gt;Laravel Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;laravel new laravel-ws-example&lt;/code&gt; on my local machine.&lt;br&gt;
I jump right in and install the Laravel WebSockets package using the &lt;a href="https://beyondco.de/docs/laravel-websockets/getting-started/installation"&gt;installation guide&lt;/a&gt; to install the package, publish the migrations and the configuration file.&lt;/p&gt;

&lt;p&gt;I add a little boilerplate code to the &lt;code&gt;welcome.blade.php&lt;/code&gt; file by replacing the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; so we can use that later to verify everything works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"antialiased"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center py-4 sm:pt-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max-w-6xl mx-auto sm:px-6 lg:px-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-center position-ref full-height"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content dark:text-white text-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
                        Laravel WebSockets
                    &lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

                    Currently &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"online"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; browsers are viewing this page!
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUSHER_APP_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{{ config(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;broadcasting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;) }}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APP_DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.debug&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}};&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ mix('js/app.js') }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can probably tell, the goal is to show how many browsers tabs are open viewing the page in realtime once we are done to validate everything is setup correctly.&lt;/p&gt;

&lt;p&gt;I also added the following configuration settings to my &lt;code&gt;.env&lt;/code&gt; file which configures the ID, key and secret Laravel WebSockets uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BROADCAST_DRIVER=pusher
PUSHER_APP_ID=PFKJ5W3TYTFnv7p5yVRWsBPd
PUSHER_APP_KEY=wttTXkwAPaP8pu2M25MFNv2u
PUSHER_APP_SECRET=4czbE8JbHNDRSZTUSGdEw9QQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: The ID, key and secret here are example values, please generate your own using for example &lt;a href="https://www.random.org/passwords/?num=3&amp;amp;len=24&amp;amp;format=html&amp;amp;rnd=new"&gt;random.org&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why are the &lt;code&gt;.env&lt;/code&gt; keys prefixed with &lt;code&gt;PUSHER_&lt;/code&gt; and why are we using the &lt;code&gt;pusher&lt;/code&gt; broadcast driver you may ask?&lt;br&gt;
This is because Laravel WebSockets is intended to be a drop-in replacement for &lt;a href="https://pusher.com/"&gt;Pusher&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The values we added to the &lt;code&gt;.env&lt;/code&gt; are used in the &lt;code&gt;websockets.php&lt;/code&gt; configuration file and also in the &lt;code&gt;broadcasting.php&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;It's important to not change any other values in &lt;code&gt;websockets.php&lt;/code&gt;. &lt;br&gt;
You might think you need to configure an SSL certificate file in there, you don't! &lt;br&gt;
We are going to use NGINX for SSL termination, that means NGINX handles the SSL part and forwards plain HTTP traffic to the websockets server, more about that later.&lt;/p&gt;

&lt;p&gt;I add the following connection to the &lt;code&gt;broadcasting.php&lt;/code&gt; file, this assumes I am running my websocket server on port &lt;code&gt;6001&lt;/code&gt; on the same machine as the application is running (which is the default and it will be in this example):&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="s1"&gt;'pusher'&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;'pusher'&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;'PUSHER_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;'PUSHER_APP_SECRET'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'app_id'&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;'PUSHER_APP_ID'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'options'&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;'host'&lt;/span&gt;   &lt;span class="o"&gt;=&amp;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="mi"&gt;6001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'scheme'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'http'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'useTLS'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// this is no error, we are talking without SSL to the WebSocket server from Laravel but your end-users will connect with SSL&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;I then proceed to install Laravel Echo following the &lt;a href="https://laravel.com/docs/8.x/broadcasting#client-pusher-channels"&gt;official documentation&lt;/a&gt; my Echo looks like this:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Echo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;broadcaster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pusher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;               &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUSHER_APP_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;wsHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;wsPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APP_DEBUG&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="mi"&gt;6002&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;wssPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;           &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APP_DEBUG&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="mi"&gt;6002&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;forceTLS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APP_DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;disableStats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enabledTransports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important is to note I added &lt;code&gt;wssPort&lt;/code&gt; and set &lt;code&gt;forceTLS&lt;/code&gt; to whatever &lt;code&gt;APP_DEBUG&lt;/code&gt; is not since we want that SSL goodness but not locally.&lt;/p&gt;

&lt;p&gt;You'll notice I get the app key from &lt;code&gt;window.PUSHER_APP_KEY&lt;/code&gt; and the debug state from &lt;code&gt;window.APP_DEBUG&lt;/code&gt; I have set that in &lt;code&gt;welcome.blade.php&lt;/code&gt; using the following snippet (before I load my JavaScript). It reads the app key from the broadcasting connection we setup earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUSHER_APP_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{{ config(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;broadcasting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;) }}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APP_DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.debug&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I proceed to add a proof of concept piece of code that will just simply count all users in a presence channel, I added this to my &lt;code&gt;app.js&lt;/code&gt;, don't forget to run &lt;code&gt;npm run dev&lt;/code&gt; after modifying your JS files.&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;onlineUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;update_online_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;onlineUsers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;common_room&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;here&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;users&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;onlineUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nx"&gt;update_online_counter&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;span class="nx"&gt;joining&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&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;onlineUsers&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nx"&gt;update_online_counter&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;span class="nx"&gt;leaving&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&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;onlineUsers&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nx"&gt;update_online_counter&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;This is about all the setup needed to get our example application up and running!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Presence channels are supposed to be authenticated but for this example I did not want to scaffold a user login so I took my question to Google and found some guidance on a &lt;a href="https://stackoverflow.com/questions/43341820/laravel-echo-allow-guests-to-connect-to-presence-channel"&gt;Stack Overflow&lt;/a&gt; post and adapted it for our use case. This allows an unauthenticated &lt;code&gt;common_room&lt;/code&gt; channel that everyone and their dog can join. Do not do this in you app please unless you know what you are doing!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On to the Forge!
&lt;/h2&gt;

&lt;p&gt;So the next step will be deploying this application to Forge, I uploaded my application to &lt;a href="https://github.com/stayallive/laravel-websockets-example"&gt;GitHub&lt;/a&gt;. I also created a site on a Forge server for it and deployed it using the Forge apps feature. After it was deployed I added a Let's Encrypt certificate. This can all be done from the Forge interface and requires no SSH (Forge is great!).&lt;/p&gt;

&lt;p&gt;There are two ways to proceed, the first is to use the same domain as the application but a different port than 443 (which we will do) or use a separate (sub-)domain.&lt;/p&gt;

&lt;p&gt;The first is easier since it does not require any extra setup except for some additions to the NGINX configuration (which is only some copypasta, which is about 99% of &lt;a href="https://i.imgur.com/wOsEq7N.png"&gt;your job&lt;/a&gt; anywho).&lt;/p&gt;

&lt;p&gt;The second way requires you to create a separate domain (or site in Forge terms) for the socket server to live on which allows you to run on it on an entirely different server or run it on port &lt;code&gt;443&lt;/code&gt; if that's your jam.&lt;/p&gt;

&lt;p&gt;We will use the domain your app is hosted on and make the websocket server available on a different port.&lt;/p&gt;

&lt;p&gt;To do this edit the NGINX configuration for your site in Forge and do the following. Duplicate the server block that is in there and modify the port from &lt;code&gt;443&lt;/code&gt; to &lt;code&gt;6002&lt;/code&gt; (why not &lt;code&gt;6001&lt;/code&gt; will be explained later) and replace the &lt;code&gt;location / { /* ... */ }&lt;/code&gt; block with the configuration from the &lt;a href="https://beyondco.de/docs/laravel-websockets/basic-usage/ssl#usage-with-a-reverse-proxy-like-nginx"&gt;Laravel WebSockets documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you did that the NGINX config should look a little something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# FORGE CONFIG (DO NOT REMOVE!)&lt;/span&gt;
&lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="n"&gt;forge-conf/laravel-ws-example.bouma.blog/before/*&lt;/span&gt;;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="s"&gt;[::]:443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;laravel-ws-example.bouma.blog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_tokens&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/home/forge/laravel-ws-example.bouma.blog/public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# FORGE SSL (DO NOT REMOVE!)&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/ssl/laravel-ws-example.bouma.blog/123456/server.crt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/ssl/laravel-ws-example.bouma.blog/123456/server.key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;ssl_protocols&lt;/span&gt; &lt;span class="s"&gt;TLSv1.2&lt;/span&gt; &lt;span class="s"&gt;TLSv1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_ciphers&lt;/span&gt; &lt;span class="s"&gt;TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS_AES_256_GCM_SHA384:TLS-AES-256-GCM-SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_dhparam&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/dhparams.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"SAMEORIGIN"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-XSS-Protection&lt;/span&gt; &lt;span class="s"&gt;"1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;mode=block"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="s"&gt;"nosniff"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt; &lt;span class="s"&gt;index.htm&lt;/span&gt; &lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;charset&lt;/span&gt; &lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# FORGE CONFIG (DO NOT REMOVE!)&lt;/span&gt;
    &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="nc"&gt;forge-conf/laravel-ws-example&lt;/span&gt;&lt;span class="s"&gt;.bouma.blog/server/*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="n"&gt;/index.php?&lt;/span&gt;&lt;span class="nv"&gt;$query_string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;/favicon.ico&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;log_not_found&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;/robots.txt&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;log_not_found&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;error_log&lt;/span&gt;  &lt;span class="n"&gt;/var/log/nginx/laravel-ws-example.bouma.blog-error.log&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="n"&gt;/index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;\.php$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_split_path_info&lt;/span&gt; &lt;span class="s"&gt;^(.+&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.php)(/.+)&lt;/span&gt;$&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="s"&gt;unix:/var/run/php/php8.0-fpm.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_index&lt;/span&gt; &lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="s"&gt;fastcgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.(?!well-known).*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&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;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;6002&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="s"&gt;[::]:6002&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;laravel-ws-example.bouma.blog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_tokens&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/home/forge/laravel-ws-example.bouma.blog/public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# FORGE SSL (DO NOT REMOVE!)&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/ssl/laravel-ws-example.bouma.blog/123456/server.crt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/ssl/laravel-ws-example.bouma.blog/123456/server.key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;ssl_protocols&lt;/span&gt; &lt;span class="s"&gt;TLSv1.2&lt;/span&gt; &lt;span class="s"&gt;TLSv1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_ciphers&lt;/span&gt; &lt;span class="s"&gt;TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS_AES_256_GCM_SHA384:TLS-AES-256-GCM-SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_dhparam&lt;/span&gt; &lt;span class="n"&gt;/etc/nginx/dhparams.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"SAMEORIGIN"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-XSS-Protection&lt;/span&gt; &lt;span class="s"&gt;"1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;mode=block"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="s"&gt;"nosniff"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt; &lt;span class="s"&gt;index.htm&lt;/span&gt; &lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;charset&lt;/span&gt; &lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# FORGE CONFIG (DO NOT REMOVE!)&lt;/span&gt;
    &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="nc"&gt;forge-conf/laravel-ws-example&lt;/span&gt;&lt;span class="s"&gt;.bouma.blog/server/*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt;             &lt;span class="s"&gt;http://127.0.0.1:6001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_read_timeout&lt;/span&gt;     &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_connect_timeout&lt;/span&gt;  &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_redirect&lt;/span&gt;         &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;# Allow the use of websockets&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;'upgrade'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;/favicon.ico&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;log_not_found&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;/robots.txt&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kn"&gt;log_not_found&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;error_log&lt;/span&gt;  &lt;span class="n"&gt;/var/log/nginx/laravel-ws-example.bouma.blog-error.log&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="n"&gt;/index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;\.php$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_split_path_info&lt;/span&gt; &lt;span class="s"&gt;^(.+&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.php)(/.+)&lt;/span&gt;$&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="s"&gt;unix:/var/run/php/php8.0-fpm.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_index&lt;/span&gt; &lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="s"&gt;fastcgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.(?!well-known).*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&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;span class="c1"&gt;# FORGE CONFIG (DO NOT REMOVE!)&lt;/span&gt;
&lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="n"&gt;forge-conf/laravel-ws-example.bouma.blog/after/*&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: &lt;a href="https://beyondco.de/docs/laravel-websockets/basic-usage/ssl#usage-with-a-reverse-proxy-like-nginx"&gt;the docs document&lt;/a&gt; a methods on how to run the websockets server on the same domain as your application but on a different path but I personally don't like that since it can collide with your app routes. However, it's an option!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next is opening up port &lt;code&gt;6002&lt;/code&gt; in the firewall so it's reachable from the internet. You can do that from the Network tab of your Forge server and add a rule called "Websockets" or something descriptive and port &lt;code&gt;6002&lt;/code&gt; and leave the IP's field blank (all IP's are allowed to connect to this port).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If your server is hosted by AWS EC2 make sure the assigned security group also allows inbound TCP traffic to port &lt;code&gt;6002&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After this there is just 1 thing left to do! Start up the websockets server as a daemon so it is automatically restarted in case it crashed or the server reboots!&lt;/p&gt;

&lt;p&gt;To do that in Forge go to the Daemons tab of your server and add a new daemon with the command &lt;code&gt;php artisan websockets:serve&lt;/code&gt; and set the directory to wherever your site is located on the server, in my case this is &lt;code&gt;/home/forge/laravel-ws-example.bouma.blog&lt;/code&gt;. If you are deploying with &lt;a href="https://envoyer.io"&gt;Envoyer&lt;/a&gt;/&lt;a href="https://deployer.org/"&gt;Deployer&lt;/a&gt; or something similair you might need a path like &lt;code&gt;/home/forge/laravel-ws-example.bouma.blog/current&lt;/code&gt;to point to the current path of your application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This daemon is not restarted each time your app is deployed and that's probably not a good idea (because every restart of the websockets server disconnects all clients) but keep in mind that new app key's or updates of the Laravel WebSockets package do require you to restart the daemon to take effect, something to keep in mind!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For completeness, to go with a separate (sub-)domain for your socket server to be served on you can add a new site (for example &lt;code&gt;socket.yourapp.com&lt;/code&gt;) and the only change you need to make to that site after enabling Let's Encrypt (you don't even need to deploy your app code to the site, it's just a configuration placeholder) is to replace the location block in the NGINX config with the one from the &lt;a href="https://docs.beyondco.de/laravel-websockets/1.0/basic-usage/ssl.html#usage-with-a-reverse-proxy-like-nginx"&gt;Laravel WebSockets documentation&lt;/a&gt;. And use port &lt;code&gt;443&lt;/code&gt; instead of &lt;code&gt;6002&lt;/code&gt; in your Pusher/Echo client.&lt;/p&gt;

&lt;h2&gt;
  
  
  But why port &lt;code&gt;6000&lt;/code&gt;, &lt;code&gt;6002&lt;/code&gt; and &lt;code&gt;433&lt;/code&gt;, what a mess!
&lt;/h2&gt;

&lt;p&gt;I hear ya! Let me explain a bit, it will hopefully all make sense afterwards.&lt;/p&gt;

&lt;p&gt;Here is the thing, opening an port on your server can only be done by only one application at a time (technically that is not true, but let's keep it simple here). So if we would let NGINX listen on port &lt;code&gt;6001&lt;/code&gt; we cannot start our websockets server also on port &lt;code&gt;6001&lt;/code&gt; since it will conflict with NGINX and the other way around, therefore we let NGINX listen on port &lt;code&gt;6002&lt;/code&gt; and let it proxy (NGINX is a reverse proxy after all) all that traffic to port &lt;code&gt;6001&lt;/code&gt; (the websockets server) over plain http. Stripping away the SSL so the websockets server has no need to know how to handle SSL.&lt;/p&gt;

&lt;p&gt;So NGINX will handle all the SSL magic and forward the traffic in plain http to port &lt;code&gt;6001&lt;/code&gt; on your server where the websockets server is listening for requests.&lt;/p&gt;

&lt;p&gt;The reason we are not configuring any SSL in the &lt;code&gt;websockets.php&lt;/code&gt; config and we define the &lt;code&gt;scheme&lt;/code&gt; in our &lt;code&gt;broadcasting.php&lt;/code&gt; as &lt;code&gt;http&lt;/code&gt; and use port &lt;code&gt;6001&lt;/code&gt; is to bypass NGINX and directly communicate with the websockets server locally without needing SSL which faster (and easier to configure and maintain).&lt;/p&gt;

&lt;h2&gt;
  
  
  A note about ports
&lt;/h2&gt;

&lt;p&gt;Websockets are not allowed to connect on any port you can think of... as &lt;a href="https://stackoverflow.com/a/4314070/1580028"&gt;Stack Overflow&lt;/a&gt; found out a lot of them are blocked (by browsers) and while testing I used port &lt;code&gt;6000&lt;/code&gt;, which also seems blocked, that why I used port &lt;code&gt;6002&lt;/code&gt; which works just fine.&lt;/p&gt;

&lt;p&gt;I had a hard time figuring out what was going on since no visible errors are thrown when you use a port that is blocked by the browser :( But looking at the pusher events I saw the error which mumbled about the port I choose not being allowed for a websockets connection.&lt;/p&gt;

&lt;p&gt;You can see the events of the Pusher client by running &lt;code&gt;window.Echo.connector.pusher.connection.timeline.events&lt;/code&gt; in the developer console and inspecting the entries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just show me the code already!
&lt;/h2&gt;

&lt;p&gt;Here it is: &lt;a href="https://github.com/stayallive/laravel-websockets-example"&gt;github.com/stayallive/laravel-websockets-example&lt;/a&gt;. And here you can see it running: &lt;a href="https://laravel-ws-example.bouma.blog"&gt;laravel-ws-example.bouma.blog&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait! What about Cloudflare?
&lt;/h2&gt;

&lt;p&gt;What about it? :)&lt;/p&gt;

&lt;p&gt;No really, it's a easy change make the websocket work when you are behind Cloudflare (with the orange icon enabled). Do be aware they have &lt;a href="https://support.cloudflare.com/hc/en-us/articles/200169466-Can-I-use-Cloudflare-with-WebSockets-"&gt;"limits"&lt;/a&gt; on the volume of connections that you might hit, although they seem to handle overuse pretty nice and not just blackhole your site.&lt;/p&gt;

&lt;p&gt;Cloudflare &lt;a href="https://support.cloudflare.com/hc/en-us/articles/200169156-Which-ports-will-Cloudflare-work-with-"&gt;lists some http(s) ports you are allowed to use&lt;/a&gt; other than &lt;code&gt;443&lt;/code&gt; for SSL. So changing port &lt;code&gt;6002&lt;/code&gt; in the examples above to port &lt;code&gt;2053&lt;/code&gt; will result in a working environment behind the Cloudflare proxy. Make sure you are using an https port from that list if you want it to work with SSL, so for example &lt;code&gt;2053&lt;/code&gt; not &lt;code&gt;2052&lt;/code&gt; since it does not support SSL. All ports support websockets.&lt;/p&gt;

&lt;p&gt;I used an origin certificate instead of one from Let's Encrypt on my app in Forge and changed the ports mentioned above (not forgetting to open the correct one in the firewall) and it just works (tm).&lt;/p&gt;

&lt;p&gt;here you can see it running: &lt;a href="https://laravel-ws-example-cloudflare.bouma.blog/"&gt;laravel-ws-example-cloudflare.bouma.blog&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let me know!
&lt;/h2&gt;

&lt;p&gt;I hope this helped with setting up your own websockets server on Forge in your Laravel app. &lt;a href="https://twitter.com/stayallive"&gt;Let me know&lt;/a&gt; how it went and where you got stuck/unstuck.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>guide</category>
      <category>websockets</category>
    </item>
    <item>
      <title>Setting up Let's Encrypt with NGINX on Ubuntu</title>
      <dc:creator>Alex Bouma</dc:creator>
      <pubDate>Sat, 10 Sep 2016 22:41:17 +0000</pubDate>
      <link>https://dev.to/stayallive/setting-up-let-s-encrypt-with-nginx-on-ubuntu-5f0f</link>
      <guid>https://dev.to/stayallive/setting-up-let-s-encrypt-with-nginx-on-ubuntu-5f0f</guid>
      <description>&lt;p&gt;This guide is more a reference to myself how to setup a fresh auto-renewing certificatie on a Ubuntu (any Linux distro supported by &lt;a href="https://github.com/certbot/certbot"&gt;certbot&lt;/a&gt; should work though) box.&lt;/p&gt;

&lt;p&gt;_ &lt;strong&gt;Note:&lt;/strong&gt; All commands should run as the root user so switch to the root user before starting (by running &lt;code&gt;sudo su&lt;/code&gt; or &lt;code&gt;su -&lt;/code&gt; depending on your setup)._&lt;/p&gt;

&lt;h4&gt;
  
  
  0. Setup dependencies
&lt;/h4&gt;

&lt;p&gt;We need &lt;code&gt;git&lt;/code&gt; to download &lt;a href="https://github.com/certbot/certbot"&gt;certbot&lt;/a&gt; from GitHub.&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;# Update the package repositories to install the latest&lt;/span&gt;
apt-get update

&lt;span class="c"&gt;# Install git&lt;/span&gt;
apt-get &lt;span class="nb"&gt;install &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1. Setup Let's Encrypt' certbot
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Switch to a working directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /opt

&lt;span class="c"&gt;# Clone the certbot repository into the certbot folder&lt;/span&gt;
git clone https://github.com/certbot/certbot

&lt;span class="c"&gt;# Create a directory to hold our configuration file(s)&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; /etc/certbot

&lt;span class="c"&gt;# Create a directory to hold certbot validation files&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/www/letsencrypt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Setup a certbot configuration file
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start a new file in the configuration directory we just created&lt;/span&gt;
nano /etc/certbot/domain.com.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following contents to this file:&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;# Use the webroot authenticator. &lt;/span&gt;
authenticator &lt;span class="o"&gt;=&lt;/span&gt; webroot

&lt;span class="c"&gt;# Use the following path for the webroot authenticator to use&lt;/span&gt;
webroot-path &lt;span class="o"&gt;=&lt;/span&gt; /var/www/letsencrypt

&lt;span class="c"&gt;# Generate certificates for the specified domains, add multiple domains by seperating them with a comma&lt;/span&gt;
domains &lt;span class="o"&gt;=&lt;/span&gt; domain.com, www.domain.com

&lt;span class="c"&gt;# Register certs with the following email address&lt;/span&gt;
email &lt;span class="o"&gt;=&lt;/span&gt; your@email.com

&lt;span class="c"&gt;# Use a 4096 bit RSA key instead of 2048&lt;/span&gt;
rsa-key-size &lt;span class="o"&gt;=&lt;/span&gt; 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the domain and email value with your own ofcourse :)&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Edit your domains NGINX config
&lt;/h4&gt;

&lt;p&gt;Open up your nginx vhost configuration file and add the following location block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;domain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;^~&lt;/span&gt; &lt;span class="n"&gt;/.well-known&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;allow&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;/var/www/letsencrypt/.well-known&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# ... snip ... #&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the location block in the http server block, or if you already have valid certificate you can also place it in your https server block.&lt;/p&gt;

&lt;p&gt;Apply the changes by restarting NGINX: &lt;code&gt;service nginx restart&lt;/code&gt; (ofcourse after you checked if your configuration is valid by running &lt;code&gt;service nginx configtest&lt;/code&gt;).&lt;/p&gt;

&lt;h5&gt;
  
  
  5. Request the certificate
&lt;/h5&gt;

&lt;p&gt;Execute the following command and follow the onscreen instructions to have the certificate being issued.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/opt/certbot/letsencrypt-auto certonly &lt;span class="nt"&gt;-c&lt;/span&gt; /etc/certbot/domain.com.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. Configure NGINX to use the certificate
&lt;/h4&gt;

&lt;p&gt;Change the vhost configuration to something like the following:&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;# Redirect to HTTPS&lt;/span&gt;
server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 80&lt;span class="p"&gt;;&lt;/span&gt;

    server_name domain.com

    location ^~ /.well-known &lt;span class="o"&gt;{&lt;/span&gt;
        allow all&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;alias&lt;/span&gt; /var/www/letsencrypt/.well-known&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;301 https://domain.com&lt;span class="nv"&gt;$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# HTTPS server block&lt;/span&gt;
server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 443 ssl&lt;span class="p"&gt;;&lt;/span&gt;

    server_name domain.com&lt;span class="p"&gt;;&lt;/span&gt;

    ssl on&lt;span class="p"&gt;;&lt;/span&gt;
    ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem&lt;span class="p"&gt;;&lt;/span&gt;
    ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem&lt;span class="p"&gt;;&lt;/span&gt;

    location ^~ /.well-known &lt;span class="o"&gt;{&lt;/span&gt;
        allow all&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;alias&lt;/span&gt; /var/www/letsencrypt/.well-known&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;# ... snip ... #&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the changes by restarting NGINX: &lt;code&gt;service nginx restart&lt;/code&gt; (ofcourse after you checked if your configuration is valid by running &lt;code&gt;service nginx configtest&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  7. Check if everything is working
&lt;/h4&gt;

&lt;p&gt;Visit your domain to see if the browser adds the green padlock and run your site through &lt;a href="https://www.ssllabs.com/ssltest/"&gt;SSL Labs&lt;/a&gt; to validate all is correct and secure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;I am focussing on the minimal changes to make the certificate work and enable HTTPS. However there are a lot of settings and considerations to make it actually secure and recieve the A+ rating on &lt;a href="https://www.ssllabs.com/ssltest/"&gt;SSL Labs&lt;/a&gt;. For more info consult:&lt;/em&gt; &lt;a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html"&gt;https://raymii.org/strong-ssl-security-on-nginx&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  8. Auto renew the certificate
&lt;/h4&gt;

&lt;p&gt;For this we are going to use a cron script that runs each month and updates our certificate and restarts NGINX.&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;# Create a new monthly cron file&lt;/span&gt;
nano /etc/cron.monthly/renew-ssl-certificates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following contents to that file:&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;#!/bin/bash&lt;/span&gt;

/opt/certbot/letsencrypt-auto certonly &lt;span class="nt"&gt;-c&lt;/span&gt; /etc/certbot/domain.com.conf &lt;span class="nt"&gt;--renew-by-default&lt;/span&gt;

service nginx restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to change &lt;code&gt;/etc/certbot/domain.com.conf&lt;/code&gt; to whatever your own config file is called.&lt;/p&gt;

&lt;p&gt;The last step is to make the renew cron executable, for that run:&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;chmod&lt;/span&gt; +x /etc/cron.monthly/renew-ssl-certificates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  9. Profit!
&lt;/h4&gt;

&lt;p&gt;You now have a &lt;em&gt;free&lt;/em&gt; Let's Encrypt certificate up and running that auto renews without you having to lift a finger :) Great!&lt;/p&gt;

</description>
      <category>server</category>
      <category>security</category>
      <category>linux</category>
      <category>letsencrypt</category>
    </item>
    <item>
      <title>How to store user id in the Laravel session table</title>
      <dc:creator>Alex Bouma</dc:creator>
      <pubDate>Mon, 31 Aug 2015 23:58:02 +0000</pubDate>
      <link>https://dev.to/stayallive/how-to-store-user-id-in-the-laravel-session-table-2fm3</link>
      <guid>https://dev.to/stayallive/how-to-store-user-id-in-the-laravel-session-table-2fm3</guid>
      <description>&lt;p&gt;Sometimes you want to store the user id with the session so you can purge all sessions or even a single session creating a more secure system for your users, or maybe you want to see how many times a user is logged in. There are many use cases but it's not possible by default... so let's implement this nifty feature :)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: this is not needed in Laravel &lt;strong&gt;5.2&lt;/strong&gt; since this comes out of the box&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Note: this guide only applies for the &lt;code&gt;database&lt;/code&gt; session driver, other drivers do not support this.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's modify the migration first:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Schema\Blueprint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Migrations\Migration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateSessionTable&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Migration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Run the migrations.
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'session.table'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unsigned&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// You can even add a foreign key constraint if you want :)&lt;/span&gt;
            &lt;span class="c1"&gt;//$table-&amp;gt;foreign('user_id')-&amp;gt;references('id')-&amp;gt;on('users')-&amp;gt;onUpdate('CASCADE')-&amp;gt;onDelete('CASCADE');&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'payload'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'last_activity'&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;span class="cd"&gt;/**
     * Reverse the migrations.
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;dropIfExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'session.table'&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;We add a unsigned integer field representing our user to the default fields, we allow null since users that are not logged in have no user id. Run &lt;code&gt;php artisan migrate&lt;/code&gt; to run the migration.&lt;/p&gt;

&lt;p&gt;Next we need to add our custom driver since we need to override a method on the database session driver provided by Laravel.&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseSessionHandler&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Illuminate\Session\DatabaseSessionHandler&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * {@inheritDoc}
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sessionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                &lt;span class="s1"&gt;'payload'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'last_activity'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'user_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user_id&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;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$sessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'payload'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'last_activity'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'user_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user_id&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;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;We also need a service provider to register our new driver with Laravel, I used a different driver name (&lt;code&gt;app.database&lt;/code&gt;) but you could also override the default database driver (called &lt;code&gt;database&lt;/code&gt;) if you want.&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Providers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Session\DatabaseSessionHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SessionServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Register the service provider.
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app.database'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$lifetime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'session.lifetime'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'session.table'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'session.connection'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DatabaseSessionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$lifetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the service provider to the providers array in your &lt;code&gt;config/app.php&lt;/code&gt; and change the driver name to &lt;code&gt;app.database&lt;/code&gt; in your &lt;code&gt;config/session.php&lt;/code&gt; config file.&lt;/p&gt;

&lt;p&gt;If you now browse around your app and log in and out you will see the session table add and remove the user id accordingly.&lt;/p&gt;

&lt;p&gt;Now you could add a Eloquent model for the sessions table and add the relation to your users model and query away on the sessions :)&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
    </item>
  </channel>
</rss>
