Nginx for FreePBX

On Debian 10, PHP 7.3, FreePBX 15 (the configuration I have been working on to help push current PHP compatibility) I set up a new server with Nginx + PHP-FPM instead of Apache + mod_php and thought I would share my configuration notes here.

Nginx configuration is overall simpler than Apache, but it does not use .htaccess files, so the settings that otherwise would be handled by Apache’s .htaccess need to be handled in the server configuration.

First, remove apache if it’s installed.

Install nginx and php-fpm: apt-get install nginx php-fpm

Make the same mods to /etc/php/7.3/fpm/php.ini that you would if using apache:

  • sed -i 's/\(^upload_max_filesize = \).*/\120M/' /etc/php/7.3/fpm/php.ini
  • sed -i 's/\(^memory_limit = \).*/\1256M/' /etc/php/7.3/fpm/php.ini

Set FPM to use the asterisk user by editing /etc/php/7.3/fpm/pool.d/www.conf and changing user =, group =, listen.owner =, and listen.group = to asterisk. (Write your own sed if you want :wink: )

Now to nginx. Edit /etc/nginx/nginx.conf and there also set user to asterisk. Other defaults are ok.

Finally you set up your site by editing the /etc/nginx/sites-enabled/default file or moving it aside and building your own. Here is mine configured for FreePBX. Replace HOSTNAME with your hostname.

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # Omit next four lines if not using HTTPS. Cert/key locations work
    # for Letsencrypt-generated cert from Certificate Manager.
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    ssl_certificate /etc/asterisk/keys/HOSTNAME/fullchain.pem;
    ssl_certificate_key /etc/asterisk/keys/HOSTNAME/private.pem;

    root /var/www/html;

    index index.html index.htm index.nginx-debian.html index.php;

    server_name HOSTNAME;  # don't use _ or FreePBX may complain about referer

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;  # server defaults are good
        fastcgi_pass unix:/run/php/php7.3-fpm.sock;
        fastcgi_param HTACCESS on;  # disables FreePBX htaccess warning
    }

    # 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;

}
3 Likes

Nice one as ever @billsimon I’ve been using your recipe for a while, (now on Debian 10. )

Awhile ago I disallowed IP based connections to voip services allowing only (domainname:!5000-5999), it was a very good thing.

I found

Preliminary deployments show all the nice folks in iceland/holland/india that ‘fingerprint match’ freepbi’s by IP address and share the wealth are getting cut off at the pass. ( I never found a reasonable solution for apache2)

So, no reason nginx cant replace httpd on RH based things , anyone want to dirty a hand?

I assume that you do the same for anything web based (admin GUI, UCP, provisioning), so I’m not sure that I understand your post. It sounds like you are trying to filter based on IP geo. IMO that’s nearly worthless, given that you already filter based on domain name, which should block virtually 100% of random scanners. Anyone targeting your system specifically will almost certainly know to launch attacks from addresses in your country.

Please don;t assume, we all know where that gets us:-)

and no, it is nothing to do with geo anything, look at your logs, all of them. Is there anything of any interest to you that was sent to you that is anonymous? .

Likely, no to that, so calls to [email protected] likely good, calls to [email protected] pretty well no.

the http(s) protocol always arrive at your ip , that is true even if the originator sent it to your url, BUT you are only interested in connections originally sent to your url. .

That nginx can now differentially route by name,port,ipaddress between source and destination is actually HUGE.

Personally to me that is very definitely not worthless, YMMV of course

An example, the guy from ‘iceland’ sees your ip answers on 8089, 8084, 4443 and gets what? If he asks the same w=question to the same ports at your.url.ip.address gets something else, think about it. . .

All summed up in

{
“routes”: [
{
“match”: {
“host”: “v1.example.com
},

        "action": {
            "proxy": "http://127.0.0.1:8000"
        }
    }
]

And

{
“routes”: [
{
“match”: {
“source”: [
:8000",
"
:0-65535”
]
},

        "action": {
            "share": "/single_wildcards_w/ports_or_port_ranges/"
        }
    },

    {
        "match": {
            "destination": [
                "127.0.0.1",
                "[2002::]:8000",
                "192.168.0.11:8080-8090"
            ]
        },

        "action": {
            "share": "/single_v4_or_v6_IPs_w/ports_or_port_ranges/"
        }
    },

    {
        "match": {
            "source": [
                "10.0.0.0/8",
                "[0ff::/64]:8000",
                "10.0.0.0/32:8080-8090"
            ]
        },

        "action": {
            "share": "/CIDR_v4_or_v6_IP_ranges_w/ports_or_port_ranges/"
        }
    },

    {
        "match": {
            "destination": [
                "10.0.0.0-11.1.0.30",
                "[fe08::-feff::]:8000",
                "192.168.0.0-192.168.1.101:8080-8090"
            ]
        },

        "action": {
            "share": "/v4_or_v6_IP_ranges_w/ports_or_port_ranges/"
        }
    }
]

Apache has a VirtualHost directive that allows requests to a specific domain to be treated specially.
https://httpd.apache.org/docs/2.4/vhosts/

So, for example, you can easily set it up so
http://1.2.3.4/ returns a 403 error
http://pbx24793.mydomain.com/ redirects to https://pbx24793.mydomain.com/
https://1.2.3.4/ returns a 403 error, using a self-signed cert that doesn’t have any real domain names
https://pbx24793.mydomain.com/ gets you (depending on exact URL) to admin, UCP, provisioning
(Requests made to domain names not matching a VirtualHost are treated the same as those with just an IP address.)

If your only concern is random attacks, the above is probably adequate. It uses only standard ports, so there is nothing to fingerprint. I believe that the FreePBX firewall uses multiple ports so that (for example) UCP can be opened to additional authorized source addresses, while keeping the admin GUI more restricted. IMO, this is no more secure than using the IP-based restrictions in Apache.

Then your ‘fine’. , don’t worry about it :slight_smile:

Seriously, what type of attack do you believe that nginx resists better? The only thing I see that’s new is filtering based on the source port. That could be another level of ‘password’ that would foil an attacker not aware it was being used, though it is not easy to force your browser to use a specific external source port. I could not see this being used for anything but the admin GUI, but IMO requiring access via VPN or SSH port forwarding is simpler and more conservative.