Jailspaces is an implementation of the webspace configuration described in my article „Secure webspaces with NGINX, PHP-FPM chroots and Let's Encrypt“.

It provides an easy-to-use solution to set up secure chrooted PHP webspaces with nginx and php-fpm with a secure (A+ on Qualys SSL Labs) TLS configuration out-of-the-box.

Feature overview

  • Fully automated setup
    • Automated and individual RSA key generation
    • Automated and individual generation of Diffie–Hellman parameters
  • Easy to use commandline interface
    • Manage webspaces with one single commandline interface
  • Safety first
    • Automatic management of file permissions
    • Each webspace runs in its own chroot jail
    • PHP scripts will run as a separate user for each webspace
    • TLS (https) support with browser accepted certificates by Let's Encrypt for each webspace
    • A+ TLS configuration for each webspace by default
    • Easy certificate renewal
  • Flexible
    • You can still have individual nginx and php-fpm configurations for each webspace. Just edit the files as you are used to.


For installation Debian 9 (Stretch) is recommended. If you want to run Jailspaces on a different OS, you probably need to change some of the parameters in /etc/jailspaces/js.conf. If you did this successfully, please contact me to share your configuration.

First install nginx and php7.0-fpm as described here and optimize your nginx configuration for enhanced security and better TLS performance.

Jailspaces needs a specific system account which is used to manage the certificates. Run the following commands in order for installation.

root@webhost:~# apt-get install git sudo members python
root@webhost:~# git clone
root@webhost:~# git clone

root@webhost:~# cp -r jailspaces-js/jailspaces /etc
root@webhost:~# cp jailspaces-js/js /usr/local/sbin

root@webhost:~# useradd -b /home -s /bin/bash -m  certmanager
root@webhost:~# cp jailspaces-js/env/certmanager /etc/sudoers.d
root@webhost:~# cp jailspaces-js/env/acme_fallback.conf /etc/nginx/conf.d
root@webhost:~# cp acme-tiny/ /home/certmanager
root@webhost:~# chmod o+x /home/certmanager/

root@webhost:~# addgroup webspaceuser
root@webhost:~# mkdir /home/www
root@webhost:~# systemctl restart nginx
root@webhost:~# js tls init

The initialization will create two 4098 bit RSA keys for NGINX and Let's Encrypt and a 4098 bit Diffie–Hellman group. These operations might take some time to finish. You will get recompensed for your time with a state-of-the-art TLS configuration.

When this is done, you can start creating webspaces.

Manage webspaces

js is the commandline tool to manage your webspaces.

The simplest way to create a new webspace is to run

root@webhost:~# js create www000

which will create a new webspace with two associated domains. It is important that and already resolve to the IP address nginx listens to, since Let's Encrypt will query the domains for ownership validation to sign the requested TLS certificates.

Run js status to list information of the created webspace

root@webhost:~# js status www000
USERNAME        : www000                                             [OK]
USERGROUP       : www000                                             [OK]
PHP-FPM-CHROOT  : /data/user/www000/chroot                           [OK]
PHP-FPM-POOL    : /etc/php/7.0/fpm/pool.d/www000.conf                [DISABLED]
NGINX CONFIG    : /etc/nginx/conf.d/www000.conf                      [DISABLED]
FQDNs           : 2                                                             
TLS CERTIFICATE : Exists, valid                                      [OK]
FILE PERMISSIONS: All correct                                        [OK]
CHROOT BINDS    : All bound                                          [OK]

After creation, the webspace is disabled by default. The chroot for this webspace is in /home/user/www000/chroot, which contains a data-www000 directory from where nginx will serve files at the domains listed in FQDNs.

To enable the webspace run

root@webhost:~# js enable www000

and point your browser to one of the listed domains. You will automatically get redirected to the secure https version of the webspace. Click the link Test SSL configuration to run a test on the TLS configuration. You should get the best rating of A+.

Commandline interface

Run js without arguments to get an overview of available commands. There are lots of commands available, but you probably will only need to use create, status, enable, disable, delete and list to manage your spaces.

root@webhost:~# js
Usage: /usr/local/sbin/js <command> [<subcommand> [<subcommand>]] [<username>] [-n|-Y]

    <command> can be one of...
            List all usernames associated with webspaces

        create <username> [FQDN0 [FQDN1 [...]]]:
            Create a webspace associated with <username> with
            domains FQDN0 - FQDNn. If the domains are not provided
            from the commandline, they need to be provided interactively.

        status <username>:
            Show status of webspace associated with <username>

        enable <username> [-n]:
            Enable webspace associated with <username>
            -n prevents reload of services

        disable <username> [-n]:
            Disable webspace associated with <username>
            -n prevents reload of services

        delete <username> [-Y]:
            Delete webspace associated with <username>.
            If -Y is provided, none questions will be asked
            and the account and all data of this webspace will
            be deleted.

        fixperm <username>:
            Set permissions and ownerships in PHP-FPM chroot
            of <username> as defined in _PHP_FPM_CHROOT_DIRS

        binds list|status|bind|unbind|clean [-Y] <username>:

                List binds for <username>

                Show mount status of binds for <username>

                Mount all binds for <username>'s chroot. Mountpoints
                will be created if they do not exist.

                Unmount all binds for <username>.

            clean [-Y]:
                Unmount all binds for <username> and delete
                mountpoints for binds. Without -Y it will
                just list the pathes that would be deleted and
                ask for confirmation interactively.

        binds systemd list|create|update|clean [-Y]

             These commands manage unit files for systemd to
             automatically create mountpoints for users on boot
             and mount binds for the user's chroots.

                List all systemd unit files managed by this script.

                Create systemd units for all users.
                Same as 

                  /usr/local/sbin/js binds systemd clean -Y && /usr/local/sbin/js binds systemd create

                This is idempotent and will bring the unitfiles in sync
                with the user's chroot binds.

            clean [-Y]:
                Delete all unit files managed by this script. Without -Y it will
                just list the pathes that would be deleted and
                ask for confirmation interactively.

        tls <subcommand> [<username>]:

            _LETS_ENCRYPT_ENABLE must be set to "true" to use these commands

            <subcommand> can be one of...

                Check preconditions and setup environment
                (directories, keys) for requesting TLS
                certificates using the "refresh" subcommand.

            refresh <username> [-n]:
                Request and apply certificate for webspace
                associated with <username> if no certificate
                is available, or if the actual certificate is
                expired or about to expire.

                -n prevents reload of services

            forcerefresh <username> [-n]:
                Same as "refresh" but always gets a new certificate

                -n prevents reload of services

Certificate management

The command

root@webhost:~# js tls refresh <webspace>

will renew the certificate for the webspace if it is about to expire within 2 days (can be changed in /etc/jailspaces/js.conf. You need to setup some monitoring / cronjob by your own to automate the renewal.


The chroots for the PHP-FPM process are set up from the _PHP_FPM_CHROOT_BIND configuration specified in /etc/jailspaces/js.conf and can be extended for a specific chroot by placing a bind.conf file in /home/www/<username> listing additional binds.


The status command will show you that the new bind is missing

root@webhost:~# js status www000
CHROOT BINDS    : Binds missing                                      [MISSING]
                  /dev/random missing

to fix this run

root@webhost:~# js binds bind www000
Creating directory /data/user/www000/chroot/dev                      [DONE]
Creating mountpoint /data/user/www000/chroot/dev/random (file)       [DONE]
Mount /data/user/www000/chroot/dev/random                            [DONE]
Remount /data/user/www000/chroot/dev/random readonly                 [DONE]

After adding or removing any binds you need to update the systemd configuration, so that the new binds will be set up on boot

root@webhost:~# js binds systemd update

Modifying NGINX or PHP-FPM configuration

To change the NGINX or PHP-FPM configuration of a certain webspace, just edit the according file in /etc/nginx/conf.d/<username>.conf and /etc/php/7.0/fpm/pool.d/<username>.conf and re-enable the webspace.

root@webhost:~# js disable <username>
root@webhost:~# js enable <username>