WordPress Pretty Permalinks in Caddy v2

1. Caddy version:

v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

2. How I installed, and run Caddy:

apt install caddy
caddy start

a. System environment:

Distributor ID: Linuxmint
Description: Linux Mint 21.1
Release: 21.1
Codename: vera

Linux persephone 5.15.0-56-generic #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

b. Command:

caddy start

c. Service/unit/compose file:

Paste full file contents here.
Make sure backticks stay on their own lines,
and the post looks nice in the preview pane.

d. My complete Caddy config:

beaststore.localhost {
        root * /home/james/Development/beaststore.net
        encode gzip
        php_fastcgi unix//var/run/php/php8.1-fpm.sock

        log {
                output file /home/james/Development/beaststore.net/errors.log

3. The problem I’m having:

According to this forum post, Caddy supports WordPress Pretty Permalinks out-of-the-box.

However, all of my URLs are prepended with index.php e.g. https://beaststore.localhost/index.php/my-account/

The Permalinks page in WordPress shows the index.php file for every Permalink structure option, except the plain permalinks.

4. Error messages and/or full log output:

Please see below, the error for what I’ve already tried.

Error: adapting config using caddyfile: parsing caddyfile tokens for 'rewrite': Caddyfile:7 - Error during parsing: Wrong argument count or unexpected line ending after 'rewrite'

5. What I already tried:

I have tried some of the try_files and rewrite directives, but I haven’t found one that works. Either I get formatting errors, or it doesn’t rewrite the URLs correctly. I think that this may be because they were for Caddy v1?


rewrite / {
            to {path} {path}/ /index.php?{query}

6. Links to relevant resources:


Per https://caddyserver.com/docs/caddyfile/directives/php_fastcgi#expanded-form, the php_fastcgi directive already does exactly what WordPress needs in order to run with pretty permalinks:

	# If the requested file does not exist, try index files
	@indexFiles file {
		try_files {path} {path}/index.php index.php
		split_path .php
	rewrite @indexFiles {file_match.relative}

So you don’t need to do anything special with your config. It does, in fact, work with just the normal directive by default.

Does the ‘Custom Structure’ option allow you to edit it to remove /index.php/?

If not - does the Site Address (URL) in Settings → General have /index.php/ on the end for you to remove?

Hey @Whitestrake thanks for your prompt reply.

I can’t remove the the index.php from the custom structure, nor can I remove it from the site address.

Screenshot attached.

That’s not a problem with Caddy, that’s a problem with whatever WordPress config you’re using.

1 Like

Hey @francislavoie I’ve done a completely fresh install of WordPress and still having this issue.

I’ve included the Caddyfile and wp-config.php below. I’ve also checked the database to confirm there aren’t any strings including index.php. The only one I could see was the permalink_structure key in the wp_options table, set to /index.php/%postname%/ but this is the same as in my previous screenshot, I can’t change this value via the WP dashboard.

I am using wp core download to fetch the WordPress files, then wp config create to generate the wp-config.php file. I have also tried creating the config file via the WordPress UI, but the result is the same.


example.localhost {
	root * /home/james/Development/example.com
	encode gzip
	php_fastcgi unix//var/run/php/php8.1-fpm.sock


 * The base configuration for WordPress
 * The wp-config.php creation script uses this file during the installation.
 * You don't have to use the web site, you can copy this file to "wp-config.php"
 * and fill in the values.
 * This file contains the following configurations:
 * * Database settings
 * * Secret keys
 * * Database table prefix
 * @link https://wordpress.org/support/article/editing-wp-config-php/
 * @package WordPress

// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'example' );

/** Database username */
define( 'DB_USER', 'root' );

/** Database password */
define( 'DB_PASSWORD', 'password' );

/** Database hostname */
define( 'DB_HOST', 'localhost' );

/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );

/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

 * Authentication unique keys and salts.
 * Change these to different unique phrases! You can generate these using
 * the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
 * You can change these at any point in time to invalidate all existing cookies.
 * This will force all users to have to log in again.
 * @since 2.6.0
define( 'AUTH_KEY',         ' Y~Wy[3HlHbH;FytH.aa2}Y<cu>++jwk0I:x}R/oMe!UP$`X rq4h^gfhIbFZphx' );
define( 'SECURE_AUTH_KEY',  'SV1Yp#4]/1=y&%PG<cdU}YUst^xccaYT2>+@xl5tC=v)<pn(Si zd4L*L/<mE|JF' );
define( 'LOGGED_IN_KEY',    'm28y.<UH~KfDNhLd$k2lJ,wL_:ZwMIZeY`_6Ym$<A2^lmOF8dVf4(g{13+p;{=U7' );
define( 'NONCE_KEY',        'j?!><8Mv9!gWgq@|lsrli8L_}G@AjLe.G~RZ@Ha!,0A~*@}<*JCE-@VZT6bcIrWk' );
define( 'AUTH_SALT',        'Z=Z$T8}VV;WMx 5NhHdYsfR`9?7gQP|rOd[-|bfL<TgIei+ptwCs/YKz23 @ ,di' );
define( 'SECURE_AUTH_SALT', 'c~I:LJQ393xSs%(~Hd@2Tm2G9Q93iGj&zA4ZIg<m+>Iv08f+/Ous<`MI{z*T+qAU' );
define( 'LOGGED_IN_SALT',   'qV9i6n=<Fv2BjLh~F|FL36?.Z_ harH/zx1J>Zlem~Q/j9], s,f#]g[P03McF~4' );
define( 'NONCE_SALT',       'v}URPPas<[M*8Y[M&@YlF8nz5<W8[=-gB(yG~*1o~H+r<7l~Yd<Lsx;7Q> ^Oi`@' );


 * WordPress database table prefix.
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
$table_prefix = 'wp_';

 * For developers: WordPress debugging mode.
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 * For information on other constants that can be used for debugging,
 * visit the documentation.
 * @link https://wordpress.org/support/article/debugging-in-wordpress/
define( 'WP_DEBUG', false );

/* Add any custom values between this line and the "stop editing" line. */

/* That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
	define( 'ABSPATH', __DIR__ . '/' );

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

Well, we have no evidence that this is a problem with Caddy. Many other users run WordPress without issue. I suggest you ask on WordPress support forums for help.

Ok thank you @francislavoie.

I’ll continue investigating and get back to you if I can find out what the issue is.

Hey @francislavoie, good morning.

So I’ve been doing a bit of debugging, and I may have found something related?

In WordPress there’s this function got_url_rewrite() in /wp-admin/includes/misc.php:45. I can see it’s checking for the presence of Apache’s mod_rewrite, nginx, and IIS permalinks, but nothing related to Caddy specifically.

If I modify this function to always return true, or detect Caddy via headers, it appears to be working, and the URLs no longer have the index.php string.

Appreciate that this isn’t part of Caddy directly, but perhaps an additional check could be included as part of this function, in order to detect Caddy?

 * Returns whether the server supports URL rewriting.
 * Detects Apache's mod_rewrite, IIS 7.0+ permalink support, and nginx.
 * @since 3.7.0
 * @global bool $is_nginx
 * @return bool Whether the server supports URL rewriting.
function got_url_rewrite() {
	$got_url_rewrite = ( got_mod_rewrite() || $GLOBALS['is_nginx'] || iis7_supports_permalinks() );

	 * Filters whether URL rewriting is available.
	 * @since 3.7.0
	 * @param bool $got_url_rewrite Whether URL rewriting is available.
	return apply_filters( 'got_url_rewrite', $got_url_rewrite );


That’s more of a question for WordPress developers. I don’t know what mechanism they’re using to check the presence of web servers.

Yes, I understand, I’ll reach out to the WordPress team about it.

It’s a bit odd though as I would have thought it would have been an issue for other WordPress sites if it’s due to this got_url_rewrite call, but if they aren’t having the same issue as me with the permalinks, then I’m not sure what else it might be.

Anyway, thanks again for your help!

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