Sage 10 + DDEV + Browsersync - exposing port 3000 - 400 Bad Request

Hi there.

I’m currently trying to set up a comfortable dev environment for me and my staff. I’ve tried out a lot of different set ups and settled for using Docker + DDEV. Very intuitive and easy to use in my opinion. Also, on Windows, lightning fast when using it in combination with WSL2.

Everything works as expected when I’m building on my local machine, but ideally I would like to build on the Docker instance, so when I get a new intern, the only thing I have to show them is how to start and use the DDEV machine.

I found a couple of topics on how people are approaching the issue, but I have yet to find a working solution.

I used this example to expose port 3000 on DDEV, which seems to work. However, I’m now running into the problem where, if I run yarn dev and go to http://localhost:3000, I get 400 Bad Request - The plain HTTP request was sent to HTTPS port.

Trying different nginx configs didn’t solve my issue. But I’m sure that’s where the problem lies. This is what my (still default) config looks like:

.ddev/nginx_full/nginx-site.conf

# ddev wordpress config

# If you want to take over this file and customize it, remove the line above
# and ddev will respect it and won't overwrite the file.
# See https://ddev.readthedocs.io/en/stable/users/extend/customization-extendibility/#providing-custom-nginx-configuration

# Much of this config is adapted from
# https://codex.wordpress.org/Nginx

server {
    listen 80;
    listen 443 ssl;

    root /var/www/html/web;

    ssl_certificate /etc/ssl/certs/master.crt;
    ssl_certificate_key /etc/ssl/certs/master.key;

    include /etc/nginx/monitoring.conf;

    index index.php index.htm index.html;

    # Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
    sendfile off;
    error_log /dev/stdout info;
    access_log /var/log/nginx/access.log;

    # From wordpress demo global_restrictions.conf
    # Global restrictions configuration file.
    # Designed to be included in any server {} block.
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~ /\. {
        deny all;
    }

    # Deny access to any files with a .php extension in the uploads directory
    # Works in sub-directory installs and also in multisite network
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }

    location / {
        absolute_redirect off;
        # This is cool because no php is touched for static content.
        # include the "?$args" part so non-default permalinks doesn't break when using query string
        try_files $uri $uri/ /index.php?$args;
    }

    # pass the PHP scripts to FastCGI server listening on socket
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php-fpm.sock;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_intercept_errors off;
        # fastcgi_read_timeout should match max_execution_time in php.ini
        fastcgi_read_timeout 10m;
        fastcgi_param SERVER_NAME $host;
        fastcgi_param HTTPS $fcgi_https;
    }

    location ~* \.(png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }
    location ~* \.(js|css)$ {
        expires -1;
        log_not_found off;
    }
    include /etc/nginx/common.d/*.conf;
    include /mnt/ddev_config/nginx/*.conf;
}

web/app/themes/sage/bud.config.js

/**
 * @typedef {import('@roots/bud').Bud} bud
 *
 * @param {bud} app
 */
module.exports = (app) =>
  app
    /**
     * Application entrypoints
     *
     * Paths are relative to your resources directory
     */
    .entry({
      app: ['scripts/app.js', 'styles/app.css'],
      editor: ['scripts/editor.js', 'styles/editor.css'],
    })

    /**
     * These files should be processed as part of the build
     * even if they are not explicitly imported in application assets.
     */
    .assets([app.path('src', 'images')])

    /**
     * These files will trigger a full page reload
     * when modified.
     */
    .watch([
      'tailwind.config.js',
      'resources/views/**/*.blade.php',
      'app/View/**/*.php',
    ])

    /**
     * Target URL to be proxied by the dev server.
     *
     * This is your local dev server.
     */
    .proxy('https://my-wp-bedrock-site.ddev.site');

Is there anyone who also uses this set-up, knows why this happens, or can point me in the right direction to solve this problem? I’m not a great server admin and any help would be very appreciated. Thanks.

I managed to get it to work. Opened 3000 on HTTP and served Browsersync via the domain name on HTTP.

.ddev/docker-compose.browsersync.yaml

# Override the web container's standard HTTP_EXPOSE and HTTPS_EXPOSE
# This is to expose the browsersync port.
version: '3.6'
services:
  web:
    # ports are a list of exposed *container* ports
    expose:
      - '3000'
    environment:
      - HTTP_EXPOSE=${DDEV_ROUTER_HTTP_PORT}:80,${DDEV_MAILHOG_PORT}:8025,3000:3000

web/app/themes/sage/bud.config.js

/**
 * @typedef {import('@roots/bud').Bud} bud
 *
 * @param {bud} app
 */
module.exports = (app) =>
  app
    /**
     * Application entrypoints
     *
     * Paths are relative to your resources directory
     */
    .entry({
      app: ['scripts/app.js', 'styles/app.css'],
      editor: ['scripts/editor.js', 'styles/editor.css'],
    })

    /**
     * These files should be processed as part of the build
     * even if they are not explicitly imported in application assets.
     */
    .assets([app.path('src', 'images')])

    /**
     * These files will trigger a full page reload
     * when modified.
     */
    .watch([
      'tailwind.config.js',
      'resources/views/**/*.blade.php',
      'app/View/**/*.php',
    ])

    /**
     * Target URL to be proxied by the dev server.
     *
     * This is your local dev server.
     */
    .serve('http://my-wp-bedrock-site.ddev.site:3000')
    .proxy('http://my-wp-bedrock-site.ddev.site');
1 Like