Using Caddy instead of Apache in FreePBX

Using Caddy instead of Apache in FreePBX

I’m in the process of implementing Caddy in several applications we use internally. For now I have successfully migrated Gitea, Snipe-IT, Zabbix, and now FreePBX.

I want to share here what I did so I can get feedback, suggestions, etc. I’m posting this in Caddy and FreePBX forums.

The main reason for me to stop using the build-in web server (Apache + Certificate Manager + System Admin) in FreePBX distro is that it got complicated to administer the web certificate from a sysadmin point of view, specifically when dealing with automation and when you can’t open 80/443 to the internet.

The idea here is to completely replace Apache with Caddy, not to use Caddy as a front-end to Apache. So we need to use PHP-FPM and run it as asterisk user.

FreePBX distro: SNG7-PBX-64bit-2104-1
Caddy: 2.4.6

  1. Disable and mask Apache

    systemctl mask --now httpd
  2. Install Caddy as documented here
    Note: To use DNS challenge you need to download a Caddy binary with a plugin for your DNS provider. For testing you can install the RPM and just replace the binary.

    systemctl enable --now caddy.service
  3. Add user caddy to group asterisk, so the web server can read everything in /var/www/html.

    usermod -a -G asterisk caddy
  4. Install PHP-FPM

    yum install php56w-fpm
    systemctl enable --now php-fpm.service
  5. Make sure this values are set in /etc/php-fpm.d/www.conf

    user = asterisk
    group = asterisk
    listen.owner = asterisk = asterisk

    Or in one command:

    sed -i 's/^;\?\(user\|group\|listen.owner\|\) = .*$/\1 = asterisk/g' \

    Apply changes:

    systemctl restart php-fpm.service
  6. Edit /etc/caddy/Caddyfile {
    	root * /var/www/html
    	header {
    		Strict-Transport-Security max-age=31536000;

    Note: This Caddyfile is missing the DNS challenge configuration

    Optionally you can add some restrictions from .htaccess with something like this:

    root * /var/www/html
    handle /admin/* {
    	@blocked_admin {
    		path */.*
    		path */i18n/*
    		path */helpers/*
    		path */libraries/*
    		path */node/*
    		path */views/*php
    	respond @blocked_admin 403
    handle {
    	@blocked_main {
    		path */.*
    	respond @blocked_main 403

    Apply changes:

    systemctl reload caddy.service

That’s it. It should work. With this setup I get an A+ with

I only have two uses for the web front of FreePBX: Admin stuff (Edit extensions, routes, etc), and UCP for some users to listen to recorded calls. And it works great for this usage.

With the implementation of Caddy I no longer need the sysadmin module, and with this I removed all commercial modules. There is nothing wrong with the commercial modules, it’s just that I have not no use for them for the moment.

Please give your opinion. I’m interested in the hide .* part, which is supposed to block all . (hidden) files as the .htaccess does, but I’m not sure if that is the correct way or if I need more to add.

Updates 2022-01-05:

  • There is no need to run Caddy as asterisk user, we can let it run as caddy. As long as FPM is run by asterisk and we add the user caddy to group asterisk everything should be fine.
  • Add a Caddyfile that tries to mimic what .htaccess does.
  • This should work with WebRTC.

Thank you.


In case you weren’t doing so, use systemctl edit caddy to edit the service, better than actually modifying the service file that ships with the package:

Also, do you really need to run as the asterisk user? Can’t you just give the caddy user the same permissions? Maybe you could add the caddy user to the asterisk group, that might be enough?

Hmm. I really cannot recommend using PHP 5.6. It’s very very old, no longer gets security updates.

From a quick Google search, it should support at least PHP 7.4. But 7.4 is also EOL, would be best to use PHP 8.0 at least: PHP: Supported Versions

1 Like

I actually use Ansible and create /etc/systemd/system/caddy.service.d/override.conf with just the needed changes. But I explained it that way to be more general.

I already tried this, and it give me a lot of errors. FreePBX wants that everything is run by asterisk.

FreePBX 15 (still supported) uses PHP 5.6. FreePBX 16 can be used with PHP 7+. But for now I have not made the upgrade.

Thanks for the input.

Well, Caddy isn’t actually running the PHP code, only php-fpm does. So then only php-fpm needs to be as the asterisk user, not Caddy.

That makes sense. But what about file_server directive? isn’t that using the user Caddy runs as?

I got the user thing from some guides for Nginx with FreePBX. But some quick tests shows no visible difference.

Yes, but that’s only for reading files. So if the caddy user is part of the asterisk group (or whatever group owns the files in /var/www/html) and those files have the group read permission, then it would all work.

I think you’re right. I would have to do more testing with Caddy running as caddy user.

I thought this was needed because the asterisk user modifies /var/www/html/admin/modules to install/update modules, but apparently this is performed with PHP scripts, not directly.

Thanks for the help. This clears things a lot.

1 Like