使用Docker和Nginx作为Laravel Websocket的反向代理时的问题

发布于 2025-02-12 20:29:46 字数 8858 浏览 2 评论 0原文

我已经使用Docker和Docker-Compose设置了Laravel项目。

我已经暴露了端口6001,它是运行 websocket 默认为默认值的端口NGINX基于文档,但是当我尝试使用域连接到WS服务器时,我会在Nginx日志文件上获取此错误:

上游读取上游响应标头的过早封闭连接从上游,客户: *,服务器:site.cpm,请求:“ get/app/7f0cb504a1426efd6854a03779a1c8a9?protocol=7&; ,上游: “ http://172.19.0.5:3030/app/7f0cb504a1426efd6854a03779a03779a1c8a9?protocol = 7& protcolcocol = 7& client = js&amp

;我什至无法使用直接IP和 港口。

我还应该提到,我的服务器上没有激活任何防火墙(至少据我所知)。

nginx配置文件:

map $http_upgrade $type {
  default "web";
  websocket "ws";
}

upstream websocket {
    server php:6001;
}

server {
    listen 80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate /app/docker/nginx/certs/public-selfsigned.crt;
    ssl_certificate_key /app/docker/nginx/certs/private-selfsigned.key;
    
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

    server_name panel.melodigram.app;

    client_max_body_size 2048M;

    index index.php index.html;
    error_log  /var/log/nginx/fpm.log;
    access_log /var/log/nginx/access.log;
    root /app/public_html;

    location / {
        try_files /nonexistent @$type;
    }
    
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location @web {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }

    location @ws {
        proxy_pass http://websocket;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_read_timeout     60;
        proxy_connect_timeout  60;
        proxy_redirect         off;
    }
}

Websocet配置:websockets.php

<?php

use BeyondCode\LaravelWebSockets\Dashboard\Http\Middleware\Authorize;

return [

    /*
     * Set a custom dashboard configuration
     */
    'dashboard' => [
        'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
    ],

    /*
     * This package comes with multi tenancy out of the box. Here you can
     * configure the different apps that can use the webSockets server.
     *
     * Optionally you specify capacity so you can limit the maximum
     * concurrent connections for a specific app.
     *
     * Optionally you can disable client events so clients cannot send
     * messages to each other via the webSockets.
     */
    'apps' => [
        [
            'id' => env('PUSHER_APP_ID'),
            'name' => env('APP_NAME'),
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'path' => env('PUSHER_APP_PATH'),
            'capacity' => null,
            'enable_client_messages' => false,
            'enable_statistics' => true,
        ],
    ],

    /*
     * This class is responsible for finding the apps. The default provider
     * will use the apps defined in this config file.
     *
     * You can create a custom provider by implementing the
     * `AppProvider` interface.
     */
    'app_provider' => BeyondCode\LaravelWebSockets\Apps\ConfigAppProvider::class,

    /*
     * This array contains the hosts of which you want to allow incoming requests.
     * Leave this empty if you want to accept requests from all hosts.
     */
    'allowed_origins' => [
        //
    ],

    /*
     * The maximum request size in kilobytes that is allowed for an incoming WebSocket request.
     */
    'max_request_size_in_kb' => 250,

    /*
     * This path will be used to register the necessary routes for the package.
     */
    'path' => 'laravel-websockets',

    /*
     * Dashboard Routes Middleware
     *
     * These middleware will be assigned to every dashboard route, giving you
     * the chance to add your own middleware to this list or change any of
     * the existing middleware. Or, you can simply stick with this list.
     */
    'middleware' => [
        'web',
        Authorize::class,
    ],

    'statistics' => [
        /*
         * This model will be used to store the statistics of the WebSocketsServer.
         * The only requirement is that the model should extend
         * `WebSocketsStatisticsEntry` provided by this package.
         */
        'model' => \BeyondCode\LaravelWebSockets\Statistics\Models\WebSocketsStatisticsEntry::class,

        /**
         * The Statistics Logger will, by default, handle the incoming statistics, store them
         * and then release them into the database on each interval defined below.
         */
        'logger' => BeyondCode\LaravelWebSockets\Statistics\Logger\HttpStatisticsLogger::class,

        /*
         * Here you can specify the interval in seconds at which statistics should be logged.
         */
        'interval_in_seconds' => 60,

        /*
         * When the clean-command is executed, all recorded statistics older than
         * the number of days specified here will be deleted.
         */
        'delete_statistics_older_than_days' => 60,

        /*
         * Use an DNS resolver to make the requests to the statistics logger
         * default is to resolve everything to 127.0.0.1.
         */
        'perform_dns_lookup' => false,
    ],

    /*
     * Define the optional SSL context for your WebSocket connections.
     * You can see all available options at: http://php.net/manual/en/context.ssl.php
     */
    'ssl' => [
        /*
         * Path to local certificate file on filesystem. It must be a PEM encoded file which
         * contains your certificate and private key. It can optionally contain the
         * certificate chain of issuers. The private key also may be contained
         * in a separate file specified by local_pk.
         */
        'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),

        /*
         * Path to local private key file on filesystem in case of separate files for
         * certificate (local_cert) and private key.
         */
        'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),

        /*
         * Passphrase for your local_cert file.
         */
        'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
    ],

    /*
     * Channel Manager
     * This class handles how channel persistence is handled.
     * By default, persistence is stored in an array by the running webserver.
     * The only requirement is that the class should implement
     * `ChannelManager` interface provided by this package.
     */
    'channel_manager' => \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManagers\ArrayChannelManager::class,
];

Docker撰写文件:Docker-compose.yml

version: '3'

services:
  nginx:
    build: ./docker/nginx
    restart: always
    command: ['nginx-debug', '-g', 'daemon off;']
    volumes:
      - ./:/app/
      - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    ports:
      - 80:80
      - 443:443
    depends_on:
      - php
    networks:
      - internal
  php:
    build: ./
    image: zagreus/melodi
    container_name: zagreus-melodi
    restart: always
    working_dir: /app
    command: [ "bash", "/app/docker/initialize.sh" ]
    ports:
      - 6001:6001
    volumes:
      - ./:/app/
      - ./docker/php/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf
    depends_on:
      - database
      - redis
    networks:
      - internal
  database:
    image: mariadb
    container_name: melodi-database
    restart: always
    environment:
      - MARIADB_RANDOM_ROOT_PASSWORD=yes
      - MARIADB_DATABASE=${DB_DATABASE:?DB_DATABASE not entered}
      - MARIADB_USER=${DB_USERNAME:?DB_USERNAME not entered}
      - MARIADB_PASSWORD=${DB_PASSWORD?DB_PASSWORD not entered}
    volumes:
      - ${DB_PERSIST_PATH:?DB_PERSIST_PATH not entered}:/var/lib/mysql
    networks:
      - internal
    # ports:
    #   - 3306:3306
  phpmyadmin:
    image: phpmyadmin
    container_name: melodi-phpmyadmin
    restart: always
    depends_on:
      - database
    ports:
      - 8080:80
    networks:
      - internal
    environment:
      - PMA_HOST=database
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD:-password}
      - PMA_ARBITRARY=1
      - UPLOAD_LIMIT=2G
  redis:
    image: redis:7.0.0-bullseye
    container_name: melodi-redis
    restart: always
    networks:
      - internal
networks:
  internal:
      driver: bridge

感谢您给出这个问题的时间&lt; 3

I've set up my Laravel project with docker and docker-compose.

I've exposed port 6001, which is the port for running the WebSocket as default, and configured Nginx based on the documentation, but when I try to connect to my WS server using my domain, I get this error on the Nginx log file:

upstream prematurely closed connection while reading response header from upstream, client: *, server: site.cpm, request: "GET /app/7f0cb504a1426efd6854a03779a1c8a9?protocol=7&client=js&version=7.0.6&flash=false HTTP/1.1", upstream: "http://172.19.0.5:3030/app/7f0cb504a1426efd6854a03779a1c8a9?protocol=7&client=js&version=7.0.6&flash=false", host: "site.com"

Another weird problem is now I can't even connect to my WS server using direct IP and port.

I should also mention that there isn't any firewall activated on my server (at least, as far as I know).

Nginx config file:

map $http_upgrade $type {
  default "web";
  websocket "ws";
}

upstream websocket {
    server php:6001;
}

server {
    listen 80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate /app/docker/nginx/certs/public-selfsigned.crt;
    ssl_certificate_key /app/docker/nginx/certs/private-selfsigned.key;
    
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

    server_name panel.melodigram.app;

    client_max_body_size 2048M;

    index index.php index.html;
    error_log  /var/log/nginx/fpm.log;
    access_log /var/log/nginx/access.log;
    root /app/public_html;

    location / {
        try_files /nonexistent @$type;
    }
    
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location @web {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }

    location @ws {
        proxy_pass http://websocket;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_read_timeout     60;
        proxy_connect_timeout  60;
        proxy_redirect         off;
    }
}

Websocet config: websockets.php

<?php

use BeyondCode\LaravelWebSockets\Dashboard\Http\Middleware\Authorize;

return [

    /*
     * Set a custom dashboard configuration
     */
    'dashboard' => [
        'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
    ],

    /*
     * This package comes with multi tenancy out of the box. Here you can
     * configure the different apps that can use the webSockets server.
     *
     * Optionally you specify capacity so you can limit the maximum
     * concurrent connections for a specific app.
     *
     * Optionally you can disable client events so clients cannot send
     * messages to each other via the webSockets.
     */
    'apps' => [
        [
            'id' => env('PUSHER_APP_ID'),
            'name' => env('APP_NAME'),
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'path' => env('PUSHER_APP_PATH'),
            'capacity' => null,
            'enable_client_messages' => false,
            'enable_statistics' => true,
        ],
    ],

    /*
     * This class is responsible for finding the apps. The default provider
     * will use the apps defined in this config file.
     *
     * You can create a custom provider by implementing the
     * `AppProvider` interface.
     */
    'app_provider' => BeyondCode\LaravelWebSockets\Apps\ConfigAppProvider::class,

    /*
     * This array contains the hosts of which you want to allow incoming requests.
     * Leave this empty if you want to accept requests from all hosts.
     */
    'allowed_origins' => [
        //
    ],

    /*
     * The maximum request size in kilobytes that is allowed for an incoming WebSocket request.
     */
    'max_request_size_in_kb' => 250,

    /*
     * This path will be used to register the necessary routes for the package.
     */
    'path' => 'laravel-websockets',

    /*
     * Dashboard Routes Middleware
     *
     * These middleware will be assigned to every dashboard route, giving you
     * the chance to add your own middleware to this list or change any of
     * the existing middleware. Or, you can simply stick with this list.
     */
    'middleware' => [
        'web',
        Authorize::class,
    ],

    'statistics' => [
        /*
         * This model will be used to store the statistics of the WebSocketsServer.
         * The only requirement is that the model should extend
         * `WebSocketsStatisticsEntry` provided by this package.
         */
        'model' => \BeyondCode\LaravelWebSockets\Statistics\Models\WebSocketsStatisticsEntry::class,

        /**
         * The Statistics Logger will, by default, handle the incoming statistics, store them
         * and then release them into the database on each interval defined below.
         */
        'logger' => BeyondCode\LaravelWebSockets\Statistics\Logger\HttpStatisticsLogger::class,

        /*
         * Here you can specify the interval in seconds at which statistics should be logged.
         */
        'interval_in_seconds' => 60,

        /*
         * When the clean-command is executed, all recorded statistics older than
         * the number of days specified here will be deleted.
         */
        'delete_statistics_older_than_days' => 60,

        /*
         * Use an DNS resolver to make the requests to the statistics logger
         * default is to resolve everything to 127.0.0.1.
         */
        'perform_dns_lookup' => false,
    ],

    /*
     * Define the optional SSL context for your WebSocket connections.
     * You can see all available options at: http://php.net/manual/en/context.ssl.php
     */
    'ssl' => [
        /*
         * Path to local certificate file on filesystem. It must be a PEM encoded file which
         * contains your certificate and private key. It can optionally contain the
         * certificate chain of issuers. The private key also may be contained
         * in a separate file specified by local_pk.
         */
        'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),

        /*
         * Path to local private key file on filesystem in case of separate files for
         * certificate (local_cert) and private key.
         */
        'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),

        /*
         * Passphrase for your local_cert file.
         */
        'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
    ],

    /*
     * Channel Manager
     * This class handles how channel persistence is handled.
     * By default, persistence is stored in an array by the running webserver.
     * The only requirement is that the class should implement
     * `ChannelManager` interface provided by this package.
     */
    'channel_manager' => \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManagers\ArrayChannelManager::class,
];

Docker compose file: docker-compose.yml

version: '3'

services:
  nginx:
    build: ./docker/nginx
    restart: always
    command: ['nginx-debug', '-g', 'daemon off;']
    volumes:
      - ./:/app/
      - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    ports:
      - 80:80
      - 443:443
    depends_on:
      - php
    networks:
      - internal
  php:
    build: ./
    image: zagreus/melodi
    container_name: zagreus-melodi
    restart: always
    working_dir: /app
    command: [ "bash", "/app/docker/initialize.sh" ]
    ports:
      - 6001:6001
    volumes:
      - ./:/app/
      - ./docker/php/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf
    depends_on:
      - database
      - redis
    networks:
      - internal
  database:
    image: mariadb
    container_name: melodi-database
    restart: always
    environment:
      - MARIADB_RANDOM_ROOT_PASSWORD=yes
      - MARIADB_DATABASE=${DB_DATABASE:?DB_DATABASE not entered}
      - MARIADB_USER=${DB_USERNAME:?DB_USERNAME not entered}
      - MARIADB_PASSWORD=${DB_PASSWORD?DB_PASSWORD not entered}
    volumes:
      - ${DB_PERSIST_PATH:?DB_PERSIST_PATH not entered}:/var/lib/mysql
    networks:
      - internal
    # ports:
    #   - 3306:3306
  phpmyadmin:
    image: phpmyadmin
    container_name: melodi-phpmyadmin
    restart: always
    depends_on:
      - database
    ports:
      - 8080:80
    networks:
      - internal
    environment:
      - PMA_HOST=database
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD:-password}
      - PMA_ARBITRARY=1
      - UPLOAD_LIMIT=2G
  redis:
    image: redis:7.0.0-bullseye
    container_name: melodi-redis
    restart: always
    networks:
      - internal
networks:
  internal:
      driver: bridge

Thanks for the time which you give to this question <3

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雨后咖啡店 2025-02-19 20:29:46

好的,所以我发现问题是即使我使用nginx作为反向代理,我的nginx本身正在处理SSL,我也填写了laravel_websockets_sssl_local_cert_cert_certlaravel_weavel_websockets_sssl_local_local_local_pk >在我的环境文件中引起问题。

因此,如果您将NGINX用作反向代理,请确保在容器上打开端口后,只需让Nginx处理SSL,并且不要在此软件包上再次配置它。

Ok, so I found out that the problem was even though I was using Nginx as a reverse proxy and my Nginx was handling SSL by itself, I've also filled LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT and LARAVEL_WEBSOCKETS_SSL_LOCAL_PK in my environment file that causes the problem.

So if you are using Nginx as a reverse proxy, after making sure that the port is open on your container, just let Nginx handle the SSL and don't configure it again on this package.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文