Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PusherBroadcaster 404 Error on Production Server #112

Closed
dysTOS opened this issue Mar 22, 2024 · 3 comments
Closed

PusherBroadcaster 404 Error on Production Server #112

dysTOS opened this issue Mar 22, 2024 · 3 comments
Assignees

Comments

@dysTOS
Copy link

dysTOS commented Mar 22, 2024

Reverb Version

1.x

Laravel Version

11.0.7

PHP Version

8.2

Description

First, I already have a fully working reverb websocket connection when developing locally - Private-Channels, Authentication, Notifications, SSL - everything works like a charm. My frontend is a seperate angular-application running on a different subdomain.

On my production server the websocket connection is also established as it should be. BUT when firing a notification that should be broadcasted via reverb, the queued job fails with the following error:

Illuminate\Broadcasting\BroadcastException: Pusher error: <!DOCTYPE html>
<html lang="en">
    // some html that says 404 not found
</html>

. in /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php:164
Stack trace:
#0 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastEvent.php(92): Illuminate\Broadcasting\Broadcasters\PusherBroadcaster->broadcast()
#1 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Illuminate\Broadcasting\BroadcastEvent->handle()
#2 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/Util.php(41): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#3 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure()
#4 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\Container\BoundMethod::callBoundMethod()
#5 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/Container.php(662): Illuminate\Container\BoundMethod::call()
#6 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(128): Illuminate\Container\Container->call()
#7 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\Bus\Dispatcher->Illuminate\Bus\{closure}()
#8 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#9 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(132): Illuminate\Pipeline\Pipeline->then()
#10 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(123): Illuminate\Bus\Dispatcher->dispatchNow()
#11 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\Queue\CallQueuedHandler->Illuminate\Queue\{closure}()
#12 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#13 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(122): Illuminate\Pipeline\Pipeline->then()
#14 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(70): Illuminate\Queue\CallQueuedHandler->dispatchThroughMiddleware()
#15 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/Jobs/Job.php(102): Illuminate\Queue\CallQueuedHandler->call()
#16 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(439): Illuminate\Queue\Jobs\Job->fire()
#17 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(389): Illuminate\Queue\Worker->process()
#18 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(176): Illuminate\Queue\Worker->runJob()
#19 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(139): Illuminate\Queue\Worker->daemon()
#20 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(122): Illuminate\Queue\Console\WorkCommand->runWorker()
#21 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Illuminate\Queue\Console\WorkCommand->handle()
#22 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/Util.php(41): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#23 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure()
#24 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\Container\BoundMethod::callBoundMethod()
#25 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Container/Container.php(662): Illuminate\Container\BoundMethod::call()
#26 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Console/Command.php(212): Illuminate\Container\Container->call()
#27 /var/www/vhosts/example.com/api.example.com/vendor/symfony/console/Command/Command.php(279): Illuminate\Console\Command->execute()
#28 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Console/Command.php(181): Symfony\Component\Console\Command\Command->run()
#29 /var/www/vhosts/example.com/api.example.com/vendor/symfony/console/Application.php(1049): Illuminate\Console\Command->run()
#30 /var/www/vhosts/example.com/api.example.com/vendor/symfony/console/Application.php(318): Symfony\Component\Console\Application->doRunCommand()
#31 /var/www/vhosts/example.com/api.example.com/vendor/symfony/console/Application.php(169): Symfony\Component\Console\Application->doRun()
#32 /var/www/vhosts/example.com/api.example.com/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(196): Symfony\Component\Console\Application->run()
#33 /var/www/vhosts/example.com/api.example.com/artisan(35): Illuminate\Foundation\Console\Kernel->handle()
#34 {main}

I already thought of a problem in the .env file - but I could not find a solution so far...

REVERB_APP_ID=app_id
REVERB_APP_KEY=app_key
REVERB_APP_SECRET=app_secret
REVERB_HOST=subdomain-of-my-laravel-backend.example.com // also tried with localhost and frontend-subdomain
REVERB_PORT=443 // this is also the default value in the config/reverb.php 
REVERB_SCHEME=https

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

Steps To Reproduce

sorry for missing out that

@joedixon
Copy link
Collaborator

Hi @dysTOS, what does your Nginx (or equivalent) configuration look like?

@dysTOS
Copy link
Author

dysTOS commented Mar 26, 2024

Thanks for your reply @joedixon !
I was able to get this partially solved in the meanwhile.

I have upgraded laravel/framework to 11.0.8 and did some changes to my webserver-configuration and .env variables, but went back to settings i already had before in the end, so unfortunately I am not sure what solved this issue exactly.

Here are my current configurations and relevant settings:

Backend: api.example.com (running in a Plesk Environment with Apache + Nginx as reverse proxy)
Frontend: app.example.com (Angular SPA)

Frontend (Typescript)

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

// invoked on init
(window as any).Pusher = Pusher;
    this._echo = new Echo({
      broadcaster: 'reverb',
      key: 'appkey',
      wsHost: 'api.example.com',
      wsPort: 443,
      wssPort: 443,
      forceTLS: true,
      enabledTransports: ['ws', 'wss'],
      authorizer: (channel, options) => {
        return {
          authorize: (socketId, callback) => {
            firstValueFrom(
              this.httpClient.post('https://api.example.com/api/broadcasting/auth', {
                socket_id: socketId,
                channel_name: channel.name,
              })
            )
              .then((response) => {
                callback(false, response);
              })
              .catch((error) => {
                callback(true, error);
              });
          },
        };
      },
    });

// invoked after ws-connection is established to subscribe to the private-channel
this._echo.private('App.Models.User.' + this.myUserService.getUserId()).notification((e) => {
          doMyStuff(e);
});

Laravel .env

APP_NAME=test
APP_ENV=production
APP_KEY=key
APP_DEBUG=true
APP_URL=https://api.example.com

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=production

BROADCAST_DRIVER=pusher
CACHE_DRIVER=file
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=database
SESSION_DRIVER=file
SESSION_LIFETIME=120

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

REVERB_APP_ID='id'
REVERB_APP_KEY='key'
REVERB_APP_SECRET='secret'
REVERB_HOST=api.example.com
REVERB_PORT=8080
REVERB_SCHEME=http

#NOT NEEDED AS FRONTEND IS SEPERATE APP
#VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
#VITE_REVERB_HOST=api.example.com
#VITE_REVERB_PORT=80
#VITE_REVERB_SCHEME=http

Laravel routes/channels.php

Broadcast::channel('App.Models.User.{userId}', function ($user, $userId) {
    return $user->id == $userId;
});

Laravel Providers/BroadcastServiceProvider.php

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // needed this because I use laravel/sanctum for authentication
        Broadcast::routes(['prefix' => 'api', 'middleware' => ['auth:sanctum']]);

        require base_path('routes/channels.php');
    }
}

PLESK additional Nginx directives

location /app/ {
	proxy_pass http://0.0.0.0:8080;
	proxy_set_header        Upgrade $http_upgrade;
	proxy_set_header        Connection "upgrade";
	proxy_http_version       1.1;
	proxy_set_header Host              $host;
	proxy_set_header X-Real-IP         $remote_addr;
	proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
}

Tried also with additional 'location /apps/', 'location /ws/', 'location /wss/' and same content, but it seems that /app/ is sufficient.

BUT there is still one issue - from 10 sent notifications only an average of 2 to 3 messages are received by my frontend - found no log-entries or failed jobs.

@dysTOS
Copy link
Author

dysTOS commented Mar 26, 2024

@joedixon please forget my last sentence - EVERY message is sent but it took up to 10 minutes until the last message was received by my frontend application. I will have a look on this and open a new issue if needed. Have a nice day! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants