question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Docker Compose - can't make laravel-echo-server and Redis work together

See original GitHub issue

I’m working on docker-compose.yml which deploys a Laravel project and its ecosystem. Almost everything works as I wish except the websocket server (laravel-echo-server). It is proxied through my Nginx container on same port than HTTP(S). When I run Docker Compose, laravel-echo-server prints ready (so I hope it suceeded to connect to Redis container) but it does not receive any event broadcasted by Laravel app to Redis. I expect the problem being a wrong IP (because of containers) or a namespace but didn’t succeed to find out.

version: '3.7'

services:

  app:
    image: laravel-app
    container_name: laravel-app
    depends_on:
      - database
      - cache
      - queue
      - scheduler
    volumes:
      - .:/var/www/html/
      - app-config-data:/var/www/.config/
    environment:
      CONTAINER_ROLE: app
    restart: on-failure

  scheduler:
    image: laravel-app
    container_name: laravel-scheduler
    depends_on:
      - cache
    volumes:
      - .:/var/www/html/
      - app-config-data:/var/www/.config/
    environment:
      CONTAINER_ROLE: scheduler
    restart: on-failure

  queue:
    image: laravel-app
    container_name: laravel-queue
    depends_on:
      - cache
    volumes:
      - .:/var/www/html/
      - app-config-data:/var/www/.config/
    environment:
      CONTAINER_ROLE: queue
    restart: on-failure

  web:
    container_name: nginx-server
    build:
      context: ./
      dockerfile: docker/nginx-server.dockerfile
      args:
        server_name: ${SERVER_NAME:-localhost}
        server_port: ${SERVER_PORT:-80}
        fpm_service: app
        fpm_port: ${FPM_PORT:-9000}
        ws_endpoint: ${WS_ENDPOINT:-/socket-io}
    depends_on:
      - app
    volumes:
      - .:/var/www/html/:ro
      - ./storage/logs/nginx:/var/log/nginx/
    ports:
      - "${HTTP_PORT:-80}:80"
      - "${HTTPS_PORT:-443}:443"
    restart: on-failure

  database:
    container_name: maria-database
    image: mariadb:10.4
    volumes:
      - db-data:/var/lib/mysql/
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    restart: on-failure

  cache:
    container_name: redis-server
    image: redis:5.0-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - cache-data:/data/
    restart: on-failure

  websocket:
    container_name: laravel-echo-server
    build:
      context: ./
      dockerfile: docker/laravel-echo-server.dockerfile
      args:
        app_url: "web:${HTTP_PORT:-80}"
        echo_redis_host: ${REDIS_HOST}
        echo_redis_port: ${REDIS_PORT}
        echo_redis_password: ${REDIS_PASSWORD}
    depends_on:
      - app
      - cache
    restart: on-failure

volumes:
  db-data:
  cache-data:
  app-config-data:

laravel-echo-server.json:

{
    "authHost": "web:80",
    "authEndpoint": "/broadcasting/auth",
    "clients": [],
    "database": "redis",
    "databaseConfig": {
        "redis": {
            "host": "cache",
            "port": "6379",
            "password": "********"
        }
    },
    "devMode": "false",
    "host": null,
    "port": "6001",
    "protocol": "http",
    "socketio": {},
    "sslCertPath": "",
    "sslKeyPath": "",
    "sslCertChainPath": "",
    "sslPassphrase": "",
    "apiOriginAllow": {
        "allowCors": true,
        "allowOrigin": "*.*",
        "allowMethods": "GET, POST",
        "allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
    }
}

Nginx vhost

server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;

    error_log /var/log/nginx/error.log error;
    access_log  /var/log/nginx/access.log main;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location /socket.io {
        proxy_pass http://websocket:6001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
       #try_files $uri /index.php =404;
       try_files $uri =404;
       fastcgi_split_path_info ^(.+\.php)(/.+)$;
       fastcgi_pass app:9000;
       fastcgi_index index.php;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Laravel Echo setup

const $echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.host,
    auth: {
        headers: {}
    }
});

$echo.channel('test').listen('TestMessage', function (event) {console.log(event);});

Laravel event example

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class TestMessage implements ShouldBroadcast
{
    use SerializesModels, InteractsWithSockets;

    public $message;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(string $message)
    {
        $this->message = $message;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('test');
    }
}

And when I broadcast this event, I get:

laravel-queue | [2019-12-10 09:01:23][xqmWLUoAZXVGlaNgfHIP2k9qK7zdZPj5] Processing: App\Events\TestMessage
laravel-queue | [2019-12-10 09:01:23][xqmWLUoAZXVGlaNgfHIP2k9qK7zdZPj5] Processed:  App\Events\TestMessage

but nothing appears in my browser console.

Maybe someone will find the problem among my config, if necessary I can share dockerfiles and bash scripts to setup the whole project.

Thanks in advance

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:10

github_iconTop GitHub Comments

1reaction
nicolashubercommented, May 4, 2020

For me everything works as expected.

docker-compose.yml

# websocket
websocket:
  image: node:10
  command: start
  entrypoint: ["yarn", "run", "websocket"]
  ports:
    - 6001:6001
  volumes:
    - ./src:/app:z
  working_dir: /app
  links:
    - redis

# redis
redis:
  image: redis
  ports:
    - 6379:6379

# Nginx
server:
  build:
    context: ./docker/nginx
  links:
    - websocket
    - laravel
  ports:
    - 443:443
  volumes:
    - ./src:/app:z
    - ./docker/nginx/certs:/etc/nginx/certs:z
    - ./docker/nginx/etc/nginx.conf:/etc/nginx/nginx.conf:z

# PHP FPM
laravel:
  build:
    context: ./docker/php-fpm
  volumes:
    - ./src:/app:z
  env_file:
    - ./docker/xdebug/xdebug.env
  links:
    - db
    - redis
    - memcache

nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile              on;
    client_max_body_size  13m;
    keepalive_timeout     3;

    gzip  on;

    # Upstream to abstract backend connection(s) for PHP.
    upstream php {
        server laravel:9000;
    }

    server {
        listen 443 ssl;
        server_name lvh.me;

        charset utf-8;

        root /app/public;
        index index.php;

        ssl_certificate /etc/nginx/certs/nginx.crt;
        ssl_certificate_key /etc/nginx/certs/nginx.key;

        location /socket.io {
            proxy_pass http://websocket:6001;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }

        location / {
            try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
            try_files       $fastcgi_script_name =404;
            fastcgi_pass    laravel:9000;
            fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include         fastcgi_params;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
            log_not_found off;
            add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
            expires off;
        }

        location ~ /\.ht {
            deny  all;
        }
    }
}

package.json

{
  "scripts": {
    "websocket": "node server.js"
  }
}

server.js

require('dotenv').config();

const env = process.env;

require('laravel-echo-server').run({
    authHost: env.APP_ENV == 'local' ? 'https://server' : env.APP_URL,
    devMode: env.APP_DEBUG,
    database: 'redis',
    databaseConfig: {
        redis: {
            host: env.REDIS_HOST,
            port: env.REDIS_PORT,
            keyPrefix: ''
        }
    },
    apiOriginAllow: {
		allowCors: true,
		allowOrigin: '*',
		allowMethods: 'GET, POST',
		allowHeaders: 'Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id'
	}
});

.env

REDIS_PREFIX=""
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

LiveEvent.php

<?php
class LiveEvent implements ShouldBroadcast
{
  public function broadcastOn()
  {
    return new PrivateChannel('private-live.' . $this->live->id);
  }
}

bootstrap.js

import Echo from 'laravel-echo'

io = require('socket.io-client');

Echo = new Echo({
  broadcaster: 'socket.io',
  host: window.location.hostname
});

let liveId = 1
Echo.private(`private-live.${liveId}`).listen('LiveEvent', data => {
  console.log(data)
})
1reaction
milewskicommented, Jan 5, 2020

Try to comment out this line in your database.php

'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
Read more comments on GitHub >

github_iconTop Results From Across the Web

Docker-compose, Laravel-echo-server and Redis connectivity ...
Redis is up and running fine, using the configuration file and ready to accept connections. docker ps shows both redis and echo-server are...
Read more >
Laravel Redis Echo Server Docker Stack - Five & Done
While working with Docker containers, it sometimes helps to modify your /etc/hosts file in order to continue using command like ./artisan.
Read more >
How To Install and Set Up Laravel with Docker Compose on ...
Docker Compose installed on your server, following Step 1 of How To Install and Use Docker Compose on Ubuntu 22.04.
Read more >
Containerize your Laravel Application with Docker Compose
Let's create the docker-compose.yml file under our working directory i.e. laravelapp. We required only two services for the basic laravel development setup.
Read more >
Laradock
docker -compose up -d nginx mysql phpmyadmin redis workspace ... If you can't find your Software in the list, build it yourself and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found