Nginx, php-fpm and SELinux enforcing on CentOS 7


I’ll cover some basic setup needed to get your own php application, installed underneath /opt , running on CentOS 7. Nginx is on the frontline passing requests to php 7.1’s fpm (php-fpm). Application will have it’s own dedicated php-fpm worker pool and user and the app’s directories will have proper SELinux labels.

Upgrading to php 7

CentOS 7 ships with venerable php 5.4 so in order to get your sockets on php 7 add Remi’s RPM repository or IUS. They both, Remi and IUS, depend on EPEL. Remi will be used in this this example.

Install php-cli and php-fpm, opcache is optional but the

30% speed boost speaks for itself. Again php-cli is optional but as lot of application ship with console commands then whatteheck.

Optional stuff like mcrypt, bcmath and mysql related.

Add user for your application

Having a user for the application (not nginx nor apache as php-fpm worker user) makes it alot easier to secure stuff. Pros include:

  • nginx only needs read access to document root which served via httpd anyway.
  • nginx doesn’t necessarily need read access to any php files given you have a single (or just a few) entry points for your application and they are located outside of document root .
  • your app won’t have any access to nginx’s files.
  • consistent ownership of application files, sessions, tmp and uploads etc.
  • sudoers for dishing out permissions to run application cli commands is easier.
  • after initial ‘extra work’ it simplifies spawning new apps and keeps them properly separated at DAC level.

I’ll add two users. dbut shall be the application ‘owner’ and his buddy in the dbut group will dbutter , the application user.

Application layout

Example application directory structure shoved under /opt/dbut

DAC permissions

Strip permissions from others to sensitive directories (originally created with umask 0022).

And grant write access for the application user by making rw directories group writable

Nginx configuration

Following will just smack 1 week expiration for the regex matched directories. As for other request Nginx will try to serve a file under root , if no file matches the request, php-fpm will handle it with a hard-coded SCRIPT_FILENAME . Only minimal amount of $_SERVER variables are available for the application itself. If you need more e.g. REMOTE_ADDR see /etc/nginx/fastcgi_params .

php-fpm configuration

A skeleton config for socket. Only nginx user can access the socket. catch_workers_output and error_log directives try to ensure errors pop up somewhere before app’s own error handler lands on the stage.

SELinux context

First I’d recommend installing this handy package for managing SELinux filesystem path contexts and port lists:

Php-fpm process runs as httpd_t (same label as Apache and Nginx) so I’ll use the following labels for filesystem:

  • httpd_sys_content_t for read-only
  • httpd_log_t for append only
  • httpd_sys_rw_content_t for read-write

As SELinux matches rules in order they created the most generic has to be created first. Making the whole application directory read-only:

Log directory gets httpd_log_t . Functions like fopen() must use mode ‘a’ or file_put_contents() must be flagged with FILE_APPEND .

Session and user_content directories will be read-write.

In case of oooops. To remove a rule

Finally restore context restorecon the whole directory recursively

and ls -Z should say something like this:

app.php of awesomium

avc: denied in audit.log and notes

If you want to see selinux denying all the things you can either flip selinux to permissive and restore stock context for the application directories

or drop all the rules created previously listed below and restorecon -r /opt/dbut

Leave a comment

About the author

Picture of Jesse

My name is Jesse Sandberg. I’m a dad, husband, DB Columnist, cyclist and a pirate from Finland. I usually write about CentOS / Linux stuff.

This blog powered by Oblog and in case you want to contact me here’s a blop of methods: