Sandboxing apps with Unix user accounts (user switching)
Relevant selection for this article:
When running web applications with Passenger, we recommend that you make use of the user account sandboxing feature, also known as user switching. This means (if you run multiple applications on a server) running each application under its own operating system user account, instead of running them all as the same user. Doing so improves the overall security of the system.
To better understand the problem, let us consider the situation with PHP. There is a problem that plagues most PHP web hosts, namely the fact that all PHP applications are run in the same user context as the web server. So for example, Joe's PHP application will be able to read Jane's PHP application's passwords. This is obviously undesirable on many servers.
Passenger's user account sandboxing feature solves this problem. This feature makes it very easy to run each application as its own operating system user. Assuming that you have correctly secured your files with the right filesystem permissions, user account sandboxing stops or limits the impact of certain classes of vulnerabilities. Going back to our example, if Joe's application has been hijacked through a vulnerability (or is intentionally malicious), then it won't be able to access Jane's passwords, assuming that Jane has secured her password files with the right permissions.
Table of contents
- Loading...
How it works
If the user account sandboxing feature is enabled, Passenger will need to know what user / group to run the application as. This is determined as follows:
-
Passenger tries to set the user and group name that you specify in passenger_user and passenger_group.
-
If the options above are not specified, Passenger tries to autodetect by looking at the owner of the application's "startup file".
-
If autodetection fails, or if the owner of the startup file is the
root
user, Passenger will set the user and group name specified in passenger_default_user and passenger_default_group instead (default:nobody
).
When is user account sandboxing enabled?
Not using Flying Passenger
In most installations user account sandboxing is already enabled. Assuming you are not using the Flying Passenger mode (this is probably the case), the following table shows the exceptions:
PassengerUserSwitching on (default) |
PassengerUserSwitching off |
|
---|---|---|
Web server has root privileges | User account sandboxing enabled. | User account sandboxing disabled. Apps are run as PassengerDefaultUser and PassengerDefaultGroup. |
Web server has no root privileges | User account sandboxing disabled. Apps are run as Apache's user. | User account sandboxing disabled. Apps are run as Apache's user. |
Using Flying Passenger
When using Flying Passenger, the effect is as follows:
Daemon run with root privileges | User account sandboxing enabled. |
---|---|
Daemon run without root privileges | User account sandboxing disabled. Apps are run as the daemon's user. |
Caveats & troubleshooting
If your application regularly encounters permission errors or fails to find certain files, then this is an indication that your application is started as a user that you did not intent it to be run as. Other symptoms include:
- The application fails to start because Bundler complains that it cannot find gems. This probably indicates that Bundler does not have read access to the directory that contains Bundler-installed gems.
- The application fails to start and its error message mentions the path
/nonexistent
. This probably indicates that your application is started as thenobody
user. This is because on many systems, thenobody
user's home directory is/nonexistent
.
To check whether it is indeed the case that your application is started as a different user than you intended to, see Finding out what user an application is running as.
The most likely reason why your application is started as nobody
is probably because your startup file is owned by root
, by nobody
or by an unknown user. To fix this, change the owner of the startup file to the owner that you want to run the application as.
Whatever user your application runs as, it must have read access to the application root, and read/write access to the application's logs
directory.
If you are setting up shared hosting, please carefully consider the security and privacy implications of allowing the user switching to be user controlled.
Enterprise Linux (Red Hat, CentOS, Rocky, Alma) caveats
If you installed Passenger through Phusion's YUM repository, and you want to disable user account sandboxing, then you must also change the location of the instance registry directory.
This is because our RPMs configure the default instance registry directory to /var/run/passenger-instreg
, which is only writable by root. If you disable user switching, then the Passenger processes will run as passenger_default_user which (as long as it's not root) won't be able to write to that directory.
Note that any alternative instance registry directory must have the proper SELinux context, allowing the web server to read and write to it. We recommend that you create a directory /var/lib/passenger-instreg
and give it the label var_run_t
:
$ sudo mkdir /var/lib/passenger-instreg $ sudo chcon -t var_run_t /var/lib/passenger-instreg
Then, in your Apache config file:
PassengerInstanceRegistryDir /var/lib/passenger-instreg
Finding out what user an application is running as
To find our what user an application is started as, first access its URL in your browser so that Passenger starts the application. For example:
$ curl http://www.example.local/
The application will now either successfully start or fail to start. If it fails to start then you will see an error page that tells you what user the application was being started as. If you do not see the error page in the browser then set passenger_friendly_error_pages on.
If the application successfully started, then run passenger-status
to find the process's PID:
---------- General information -----------
Max pool size : 6
Processes : 1
Requests in top-level queue : 0
---------- Application groups -----------
/webapps/example.local#default:
App root: /webapps/example.local
Requests in queue: 0
* PID: 16915 Sessions: 0 Processed: 1 Uptime: 2s
CPU: 0% Memory : 9M Last used: 2s ago
In the above example we see that the PID is 16915. Next, use 'ps' to find out the user that it is running as:
$ ps -o pid,user,comm -p 16915 PID USER COMM 16915 phusion Passenger RackApp: /webapps/example.local
As you can see, the application in this example is being run as user phusion
.