Vite on Laravel with Caddy

Has anyone had success using Caddy with Vite? This configuration works absolutely fine with Traefik but not Caddy and I can’t figure out why.

Dockerfile.node:

FROM node:20 AS base

############################################
# Development Image
############################################
FROM base AS development

# We can pass USER_ID and GROUP_ID as build arguments
# to ensure the node user has the same UID and GID
# as the user running Docker.
ARG USER_ID
ARG GROUP_ID

# Switch to root so we can set the user ID and group ID
USER root

# Script to handle existing group ID
RUN if getent group "$GROUP_ID" > /dev/null; then \
        moved_group_id="99$GROUP_ID"; \
        existing_group_name=$(getent group "$GROUP_ID" | cut -d: -f1); \
        echo "Moving GID of $existing_group_name to $moved_group_id..."; \
        groupmod -g "$moved_group_id" "$existing_group_name"; \
    fi

# Script to handle existing user ID
RUN if getent passwd "$USER_ID" > /dev/null; then \
        moved_user_id="99$USER_ID"; \
        existing_username=$(getent passwd "$USER_ID" | cut -d: -f1); \
        echo "Moving UID of $existing_username to $moved_user_id..."; \
        usermod -u "$moved_user_id" "$existing_username"; \
    fi

# Set the user ID and group ID for the node user
RUN groupmod -g $GROUP_ID node && usermod -u $USER_ID -g $GROUP_ID node

# Drop privileges back to node user
USER node

############################################
# CI Image
############################################
FROM base AS ci

docker-compose.dev.yml

services:
  caddy:
    build:
      target: development
      dockerfile: Dockerfile.caddy
    ports:
      - "80:80"
      - "443:443"
    networks:
      - development
    volumes:
      - ./.infrastructure/conf/caddy/dev/Caddyfile:/etc/caddy/Caddyfile
      - ./.infrastructure/conf/caddy/dev/certificates:/etc/caddy/certificates
    deploy:
      placement:
        constraints:
          - node.role==manager
      update_config:
        parallelism: 1
        delay: 5s
        order: stop-first
  php:
    build:
      target: development
      args:
        USER_ID: ${SPIN_USER_ID}
        GROUP_ID: ${SPIN_GROUP_ID}
      dockerfile: Dockerfile.php
    stop_signal: SIGTERM
    volumes:
      - .:/var/www/html/
    networks:
      - development
    depends_on:
      mariadb:
        condition: service_healthy
  node:
    build:
      target: development
      args:
        USER_ID: ${SPIN_USER_ID}
        GROUP_ID: ${SPIN_GROUP_ID}
      dockerfile: Dockerfile.node
    volumes:
      - .:/usr/src/app/
    working_dir: /usr/src/app/
    networks:
      - development
  mailpit:
    image: axllent/mailpit
    networks:
      - development
  schedule:
    build:
      target: development
      args:
        USER_ID: ${SPIN_USER_ID}
        GROUP_ID: ${SPIN_GROUP_ID}
      dockerfile: Dockerfile.php
    volumes:
      - .:/var/www/html/
    networks:
      - development
    depends_on:
      php:
        condition: service_started
  queue:
    build:
      target: development
      args:
        USER_ID: ${SPIN_USER_ID}
        GROUP_ID: ${SPIN_GROUP_ID}
      dockerfile: Dockerfile.php
    volumes:
      - .:/var/www/html/
    networks:
      - development
    depends_on:
      php:
        condition: service_healthy
  mariadb:
    image: mariadb:11.4
    networks:
      - development
    volumes:
      - ./.infrastructure/volume_data/mariadb/database_data/:/var/lib/mysql
    environment:
      MARIADB_ROOT_PASSWORD: "rootpassword"
      MARIADB_DATABASE: "laravel"
      MARIADB_USER: "mysqluser"
      MARIADB_PASSWORD: "mysqlpassword"
    ports:
      - target: 3306
        published: 3306
        mode: host
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      start_period: 10s
      interval: 10s
      timeout: 5s
      retries: 3
networks:
  development:

vite.config.js

import fs from 'fs';
import laravel from 'laravel-vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
    server: {
        host: '0.0.0.0',
        hmr: {
            host: 'vite.dev.test',
            clientPort: 443,
        },
        https: {
            key: fs.readFileSync(
                '/usr/src/app/.infrastructure/conf/caddy/dev/certificates/local-dev-key.pem',
            ),
            cert: fs.readFileSync(
                '/usr/src/app/.infrastructure/conf/caddy/dev/certificates/local-dev.pem',
            ),
        },
    },
    plugins: [
        laravel({
            input: 'resources/js/app.jsx',
            ssr: 'resources/js/ssr.jsx',
            refresh: true,
        }),
    ],
});

Caddyfile

https://vite.dev.test {
	reverse_proxy node:5173
	tls /etc/caddy/certificates/local-dev.pem /etc/caddy/certificates/local-dev-key.pem
}

https://laravel.dev.test {
	reverse_proxy php:8080

	tls /etc/caddy/certificates/local-dev.pem /etc/caddy/certificates/local-dev-key.pem
}

This works fine with Traefik but as soon as I try to use Caddy it fails.

If I visit https://vite.dev.test/ in my browser I get a 502 error.

This is the browser console for https:/laravel.dev.test:

GET
https://vite.dev.test/resources/js/app.jsx
NS_ERROR_CORRUPTED_CONTENT

GET
https://vite.dev.test/@vite/client
NS_ERROR_CORRUPTED_CONTENT

GET
https://vite.dev.test/resources/js/Pages/Auth/Login.jsx
CORS Failed

GET
https://vite.dev.test/@react-refresh
NS_ERROR_CORRUPTED_CONTENT

Loading module from “https://vite.dev.test/@react-refresh” was blocked because of a disallowed MIME type (“”).
[login](https://laravel.dev.test/login)
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://vite.dev.test/@react-refresh. (Reason: CORS request did not succeed). Status code: (null).

Loading module from “https://vite.dev.test/resources/js/Pages/Auth/Login.jsx” was blocked because of a disallowed MIME type (“”).
[login](https://laravel.dev.test/login)
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://vite.dev.test/resources/js/Pages/Auth/Login.jsx. (Reason: CORS request did not succeed). Status code: (null).

Loading module from “https://vite.dev.test/@vite/client” was blocked because of a disallowed MIME type (“”).
[login](https://laravel.dev.test/login)
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://vite.dev.test/@vite/client. (Reason: CORS request did not succeed). Status code: (null).

Loading module from “https://vite.dev.test/resources/js/app.jsx” was blocked because of a disallowed MIME type (“”).
[login](https://laravel.dev.test/login)
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://vite.dev.test/resources/js/app.jsx. (Reason: CORS request did not succeed). Status code: (null).

Does anyone have any ideas?

Sorry for the delay, holidays etc.

Are you sure port 5173 is correct? What’s in your Caddy logs? What if you use curl -vL to connect instead of your browser? Try connecting to node from inside the Caddy container (you can add curl with apk add curl)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.