Problem when routing without a .php suffix

1. Output of caddy version:

docker version
image: "caddy:2.6.2-alpine"

2. How I run Caddy:

a. System environment:

docker compose

b. Command:

Paste command here.

c. Service/unit/compose file:

version: '3.3'
services:
  caddy:
    image: "caddy:2.6.2-alpine"
    restart: unless-stopped
    env_file:
      - .env
    volumes:
      - ./domen:/usr/share/caddy/domen:ro
      - ./Caddyfile:/etc/caddy/Caddyfile  # configuration
      - caddy-config:/config  # configuration autosaves
      - caddy-data:/data  # saving certificates
    ports:
      - "80:80"
      - "443:443"
    networks:
      - app-network
    depends_on:
      - app
  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    # image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    # working_dir: /var/www
    volumes:
      - ./domen:/var/www/domen
      - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
      - app-network

  #MySQL Service
  db:
    image: percona:5.7.35
    container_name: db
    restart: unless-stopped
    tty: true
      #ports:
      #  - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - dbdata:/var/lib/mysql/
      - ./mysql/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --sql_mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

#Docker Networks
networks:
  app-network:
    driver: bridge
#Volumes
volumes:
  dbdata:
    driver: local
  caddy-data:
  caddy-config:

d. My complete Caddy config:

# See https://caddyserver.com/docs

# Email for Let's Encrypt expiration notices
{
  email {$TLS_EMAIL}
}

# "www" redirect to "non-www" version
www.{$DOMAIN_NAME} {
  redir https://{$DOMAIN_NAME}{uri}
}

{$DOMAIN_NAME} {
  # HTTPS options:
  header Strict-Transport-Security max-age=31536000;

  # Removing some headers for improved security:
  header -Server

  # Serving dynamic requests:
  root * /var/www/{$DOMAIN_NAME}

  php_fastcgi app:9000 {
    read_timeout 3s
  }
  file_server

   # Allows to use `.gz` files when available:
  encode gzip

  # Logs:
  log {
    output stdout
  }
}



3. The problem I’m having:

caddy sends to fastcgi only a request of the form
log fastcgi:

app  | 172.19.0.4 -  01/Nov/2022:15:06:41 +0000 "GET /index.php" 301
app  | 172.19.0.4 -  01/Nov/2022:15:06:41 +0000 "GET /index.php" 200

I need it to send a rout

app  | 172.19.0.4 -  01/Nov/2022:16:20:12 +0000 "GET /support/oprosy/" 200

path, are virtual, there are no folders

4. Error messages and/or full log output:

Paste logs/commands/output here.
USE THE PREVIEW PANE TO MAKE SURE IT LOOKS NICELY FORMATTED.

5. What I already tried:

{$DOMAIN_NAME} {
  # HTTPS options:
  header Strict-Transport-Security max-age=31536000;

  # Removing some headers for improved security:
  header -Server

  root * /usr/share/caddy/{$DOMAIN_NAME}

#     @canonicalPath {
#     file {
#       try_files {path}/index.php
#     }
#     not {
#       path */
#     }
#   }
  @phpFiles {
    path *.php
  }
  route {
    # redir @canonicalPath {path}/ 308
    try_files {path} {path}/index.php index.php
    reverse_proxy @phpFiles {
      to app:9000
      transport fastcgi {
        split .php
        root /var/www/{$DOMAIN_NAME}
      }
    }
    file_server
  }

   # Allows to use `.gz` files when available:
  encode gzip

  # Logs:
  log {
    output stdout
  }
}

Working nginx config:

	server {
		server_name {$DOMAIN_NAME};
		root /var/www/{$DOMAIN_NAME}/;
		index index.php;

		access_log /var/www/umi.access.log;
		error_log /var/www/umi.error.log warn;

		location @index {
			fastcgi_pass app:9000;
			fastcgi_read_timeout 3600;
			include fastcgi_params;
			fastcgi_param SCRIPT_FILENAME $document_root/index.php;
			fastcgi_param QUERY_STRING    path=$full_path&$args;
			fastcgi_param AUTHORIZATION   $http_authorization;
		}

		location ~* ^/(developerTools|errors|libs|smt|cache|xmldb|static|packages)\/.*$ {
			return 403;
		}

		location ~* (config\.ini|install\.ini|install\.log|umi\.nginx\.conf|(packer|dbview)\.php|composer\.umi\.(lock|json))$ {
			return 403;
		}

		location ~* "/(sitemap[\d]{0,}\.xml|robots\.txt|favicon\.ico|sitemap-images[\d]{0,}\.xml)$" {
			try_files $uri $uri/ @index;
		}

		location ~* ^/(ulang|autothumbs)/.*$ {
			fastcgi_pass app:9000;
			fastcgi_read_timeout 3600;
			include fastcgi_params;

			fastcgi_param SCRIPT_FILENAME $document_root/index.php;
			fastcgi_param QUERY_STRING    path=$full_path&$args;
			fastcgi_param AUTHORIZATION   $http_authorization;
		}

		location ~* ^/*(?<full_path>.*\.(json|xml))$ {
			expires 1d;
			access_log off;
			try_files $uri @index;
		}

		location ~* \.(bmp|css|doc|eot|flv|gif|htm|html|ico|jpe?g|js|otf|map|png|svg|tiff|ttf|twig|txt|webp|woff|woff2)$ {
			expires 1d;
			access_log off;
			try_files $uri =404;
		}
		location ~ \.mp4$ {
			mp4;
			mp4_buffer_size 1m;
			mp4_max_buffer_size 5m;
		}
		location ~ ^/(index|dummy|smu/installer|autothumbs|captcha|counter|cron|go-out|license_restore|save_domain_keycode|session|static_banner|updater)\.php$ {
			fastcgi_pass app:9000;
			fastcgi_read_timeout 3600;
			include fastcgi_params;
			fastcgi_param SCRIPT_FILENAME $document_root/index.php;
			fastcgi_param QUERY_STRING    path=$full_path&$args;
			fastcgi_param AUTHORIZATION   $http_authorization;
		}

		location ~ ^/(umi_smt|install|installer)\.php$ {
			fastcgi_pass app:9000;
			fastcgi_read_timeout 3600;
			include fastcgi_params;
			fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
			fastcgi_param QUERY_STRING    path=$full_path&$args;
			fastcgi_param AUTHORIZATION   $http_authorization;
		}

		location ~ ^/*(?<full_path>.*) {
			try_files /sys-temp/static-cache/$host/$uri/index.html @index;
		}

		location ~ \.(php[2-5]?|cgi|pl|fcgi|fpl|phtm|phtml|shtml|asp|jsp|twig|tpl|xslt?|git|svn|htaccess|htaccess_old|htpasswd|gitignore|gitkeep|ini|log|conf|md|sql|lock|umi\.json)$ {
			return 403;
		}

#   listen 80;
#   listen [::]:80 ipv6only=on;
		listen 443 ssl http2; # managed by Certbot
		listen [::]:443 ipv6only=on http2;
		ssl_certificate /etc/letsencrypt/live/{$DOMAIN_NAME}/fullchain.pem; # managed by Certbot
		ssl_certificate_key /etc/letsencrypt/live/{$DOMAIN_NAME}/privkey.pem; # managed by Certbot
		include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
		ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
	}
server {
    location ~ /.well-known/acme-challenge {
        allow all;
        root /var/www/{$DOMAIN_NAME};
    }
    if ($host = {$DOMAIN_NAME}) {
        return 301 https://{$DOMAIN_NAME}$request_uri;
    } # managed by Certbot


    if ($host = {$DOMAIN_NAME}) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    server_name {$DOMAIN_NAME};
    listen 80;
    listen [::]:80 ipv6only=on;
    return 404; # managed by Certbot

}

6. Links to relevant resources:

FYI, removing this header doesn’t improve security at all. Simply knowing which software is being used doesn’t help attackers. They can figure out which server software is used pretty easily by looking at patterns in the TLS handshake and such.

Modern PHP apps use an index.php entrypoint as the router. You should be reading $_SERVER['REQUEST_URI'] to get the originally requested URL, and run your routing logic based on that.

That’s not what this does. It doesn’t decode .gz files that you serve (or something like that). Instead, it compresses any textual content being served (static or dynamic) on-the-fly.

1 Like

Thanks for the comments, this example was copied from the internet.
Apparently I have an old php framework.
Full paths are passed from nginx to it, is there any way I can solve this with caddy?

Or is the problem something else?!
If it’s important, this is what the index.php file looks like

<?php
	define('CURRENT_WORKING_DIR', dirname(__FILE__));
	require_once __DIR__ . '/classes/system/bootstrap/bootstrap.php';

	use UmiCms\Service;

	$uri = Service::Request()
		->uri();

	$parameters = Service::Router()
		->resolve($uri);

	Service::ControllerFactory()
		->create($parameters)
		->execute();

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