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.


I don’t know anything about caddy, but PHP 5.6 will have trouble in FreePBX 16.

1 Like

Yes. This is for FreePBX 15.

I guess the idea would be similar to FreePBX 16.

1 Like

Maybe through @lgaetz or @mattf you could get access to add this to the wiki under How-to articles - FreePBX Documentation - Documentation

I went through a similar exercise with nginx + php-fpm a couple years ago. Nginx for FreePBX

Here’s where I pulled the .htaccess dirctives into the nginx config:

    # disallows the things that the FreePBX .htaccess files disallow
    location ~ (/\.ht|/\.git|\.ini$|/libraries|/helpers|/i18n|/node|/views/.+php$) {
        deny all;

    # from the api module .htaccess file
    rewrite ^/admin/api/([^/]*)/([^/]*)/?(.*)?$ /admin/api/api.php?module=$1&command=$2&route=$3 last;

I think we could combine our notes into a couple “Apache Alternatives” articles for the wiki.

1 Like

Community documentation is here:

@chemnic if you want to edit a wiki page with this content, that’s a good place for it.

Thanks. I’m going to refine the Caddyfile and probably write some documentation.

Yes, I got some ideas from there.

Nginx’s deny all returns 403, whine Caddy’s hide returns 404. Do you think is ok to use 404 (Not found)?

Also, in Caddy’s forum they told me running Caddy as asterisk user was not necesary since PHP-FPM was running as asterisk already. I just have to add the user caddy to the group asterisk to be able to read files in /var/www/html. I did that and it seems to work well, so I probably will remove that part form the steps.


It’ll work with WebRTC as WebRTC has nothing to do with Apache in FreePBX. Any WebRTC stuff in UCP connects directly to asterisk.


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

@chemnic Carlos I am interested in using Caddy with php-fpm and want to explore this further. Is your guide in the first post complete? Have you encountered any problems?

It works great. No issues at the moment.

Notice that my post was edited with some recommendations given by the community in this thread.

I also implemented Caddy with other PHP apps like Zabbix, Netxcloud, Snipe-IT and Pasbolt. The steps and configuration are similar.

Thank you.

1 Like

Hoping to replace Apache with Caddy as well.

Currently using FreePBX 16.0.19, PBX Distro 12.7.8-2204-1.sng7, with Asterisk 16.25.0

From comments above your Apache-to-Caddy conversion works only for FreePBX 15…yes?

Are conversion and/or Wiki instructions available for FreePBX LTS versions 16 or 18?