Phusion Passenger
Overview
Phusion Passenger (open source edition) is a mature, polyglot application server that serves Ruby, Node.js and Python web applications through nginx. It spawns and supervises your application processes, load balances requests across workers, automatically restarts crashed workers, and supports zero-downtime application restarts. passenger-status and passenger-memory-stats give you clear operational visibility.
This SecureAnyCloud image runs Passenger integrated with nginx on Ubuntu 24.04 on Azure. Passenger is an application server with no admin console or login, so there is nothing to authenticate to. Instead, the image ships two small demo apps, pre-deployed and served through Passenger, to prove that the runtime executes code on every request:
- a Ruby (Rack) app at
/that renders a live server timestamp and the worker PID - a Node.js (Express) app at
/node, running as a separate Passenger application group
Both apps render a live epoch and worker PID that change per request, so you can see Passenger executing real code rather than serving a static file.
What you get:
- Phusion Passenger 6.1 (open source edition, MIT licensed), integrated with nginx through the official Phusion APT repository (the
libnginx-mod-http-passengerdynamic module) - Ruby 3.2 (from the distribution) with the Rack gem, and Node.js 22 LTS with Express, so the polyglot runtime is real
- A Ruby (Rack) demo app at
/and a Node.js (Express) demo app at/node, each a distinct Passenger application group - A
passenger-firstboot.servicesystemd oneshot that starts nginx, confirms that the demo app answers, and writes a non-secret endpoints notes file - Secure defaults:
passenger_friendly_error_pages off(no stack traces to clients),server_tokens off, and Passenger anonymous telemetry and security-update phone-home disabled - nginx on
:80as the only public entry point, with no admin login surface and no baked credential - An Ubuntu 24.04 LTS base with the latest security patches applied at build time
- Azure Linux Agent for cloud integration and SSH key injection
- 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA
Prerequisites
Active Azure subscription, SSH public key, VNet + subnet in target region
Subscription to the Phusion Passenger listing on Azure Marketplace
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for development and light application workloads. Higher concurrency or CPU-bound apps should use Standard_D4s_v5 (4 vCPU, 16 GB RAM) or larger.
Deploy from the Azure Portal
Search for Phusion Passenger in Azure Marketplace, select the SecureAnyCloud publisher, and click Create. Allow TCP 22 (admin) and TCP 80 (HTTP) from your client networks in the network security group (NSG). Add TCP 443 if you terminate TLS on the instance.
Deploy from the Azure CLI
Run the following commands to create the resource group, network, NSG rules and VM:
RG="passenger-prod"; LOCATION="eastus"; VM_NAME="passenger-01" IMAGE_URN="sac1647283583153:phusion-passenger-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name passenger-vnet --address-prefix 10.100.0.0/16 --subnet-name passenger-subnet --subnet-prefix 10.100.1.0/24 az network nsg create -g "$RG" --name passenger-nsg az network nsg rule create -g "$RG" --nsg-name passenger-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name passenger-nsg --name allow-http --priority 110 \
--destination-port-ranges 80 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:phusion-passenger-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name passenger-vnet --subnet passenger-subnet --nsg passenger-nsg --public-ip-sku StandardConnect via SSH
Connect to the VM over SSH:
ssh azureuser@<vm-ip>nginx.service and passenger-firstboot.service start automatically on first boot. There is no admin account to set up, because Passenger has no login.
Verify Passenger and nginx
Check the Passenger version, the nginx service state and the listening port:
passenger-config --version sudo systemctl is-active nginx.service
sudo ss -tln | grep ':80 'Expected output: Passenger is present and nginx is listening on :80.
Phusion Passenger(R) 6.1.7 active LISTEN 0 511 0.0.0.0:80 0.0.0.0:* LISTEN 0 511 [::]:80 [::]:*You can also run Passenger's own install checker. It validates that the Passenger nginx module is wired up correctly:
printf '\n\n\n\n' | sudo passenger-config validate-installThe expected output ends with Everything looks good. :-).
Request the Ruby (Rack) Demo App
Passenger has no admin UI, so the demo apps are how you confirm it works. Request the Ruby app at / twice in a row:
curl -s http://127.0.0.1/
curl -s http://127.0.0.1/Expected output: the epoch and Worker PID values prove that Passenger executes the app on every request.
<!doctype html><html><head><title>Phusion Passenger - Ruby demo</title></head><body><h1>Phusion Passenger (open source)</h1><p>Ruby 3.2.3 application served by Passenger + nginx.</p><p>Server time: 2026-07-19T06:18:00Z epoch=1784441880</p><p>Worker PID: 9041</p></body></html>The epoch value increases between calls. It is an in-process, per-request value that cannot come from a cached or static file. This is the work an application server does that a plain static web server cannot.
Request the Node.js (Express) Demo App
The same image also serves a Node.js Express app at /node. It runs as a separate Passenger application group, so one server runs two languages and Passenger manages both. Request it:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/node
curl -s http://127.0.0.1/nodeExpected output:
HTTP 200 <!doctype html><html><head><title>Phusion Passenger - Node demo</title></head><body><h1>Phusion Passenger (open source)</h1><p>Node.js v22.23.1 application served by Passenger + nginx.</p><p>Server time: 2026-07-19T06:18:00.789Z epoch=1784441880</p><p>Worker PID: 9215</p></body></html>The Node.js worker has a different PID from the Ruby worker, because Passenger runs them as independent application processes.
Inspect Live Processes with passenger-status
passenger-status shows the application processes that Passenger manages. Warm both apps, then inspect them:
curl -s -o /dev/null http://127.0.0.1/
curl -s -o /dev/null http://127.0.0.1/node
sudo passenger-statusExpected output: two application groups, each with a live worker process.
Version : 6.1.7 Instance: xxxxxxxx (nginx/1.24.0 (Ubuntu) Phusion_Passenger/6.1.7) ----------- General information ----------- Max pool size : 6 App groups : 2 Processes : 2 Requests in top-level queue : 0 ----------- Application groups ----------- passenger-demo-node: App root: /opt/passenger-demo/node * PID: 9215 Sessions: 0 Processed: 2 Uptime: 2m 25s passenger-demo-ruby: App root: /opt/passenger-demo/ruby * PID: 9041 Sessions: 0 Processed: 31 Uptime: 2m 32sPassenger spawns these workers on demand and automatically restarts any that crash. If you kill a worker PID, the next request transparently spawns a replacement.
Check Memory Use and Endpoint Notes
passenger-memory-stats reports the memory used by the Passenger watchdog, the Passenger core and each application worker. Run it, then read the endpoint notes file:
sudo passenger-memory-stats
sudo cat /var/lib/sac/data/passenger-endpoints.notesExpected output: the notes file lists the demo URLs and where to deploy your own app. Passenger has no credentials to rotate.
# Phusion Passenger — Endpoint Notes
# Generated on first boot by passenger-firstboot.service
# PASSENGER_RUBY_DEMO_URL=http://<vm-ip>/ PASSENGER_NODE_DEMO_URL=http://<vm-ip>/node PASSENGER_APP_ROOT=/opt/passenger-demo INSPECT_PROCESSES=Run 'sudo passenger-status' to see live application process groups.Deploy Your Own App
Passenger serves any Ruby/Rack, Node.js or Python app. Copy your app to the VM under /opt/passenger-demo/ (or a directory of your choice):
scp -r ./myapp azureuser@<vm-ip>:/tmp/myapp ssh azureuser@<vm-ip> 'sudo mv /tmp/myapp /opt/myapp && sudo chown -R ppdemo:ppdemo /opt/myapp'Then point nginx at your app. For a Ruby/Rack app, set the server root to its public/ directory and add passenger_enabled on;. For a Node.js app, add a location block with passenger_app_type node; and passenger_startup_file app.js;.
The bundled /etc/nginx/sites-available/sac-passenger vhost is a working reference for both patterns. After editing, validate the configuration and reload nginx:
sudo nginx -t && sudo systemctl reload nginxRun these commands against your own app on your own VM.
Server Components
The image places these components at the following paths:
- Passenger nginx module config: /etc/nginx/conf.d/mod-http-passenger.conf
- nginx vhost: /etc/nginx/sites-available/sac-passenger
- Ruby (Rack) demo app: /opt/passenger-demo/ruby/config.ru
- Node.js (Express) demo app: /opt/passenger-demo/node/app.js
- Application user: ppdemo (unprivileged system user)
- Logs: systemd journal (journalctl -u nginx.service) and /var/log/nginx/
- Firstboot script: /usr/local/sbin/passenger-firstboot.sh
- Firstboot service: /etc/systemd/system/passenger-firstboot.service
- Endpoint notes: /var/lib/sac/data/passenger-endpoints.notes (mode 0644)
- Firstboot sentinel: /var/lib/sac/data/passenger-firstboot.done
Managing Passenger and nginx
Passenger runs inside nginx, so managing the web server also manages the application server. Check the service, reload it, and inspect the processes:
sudo systemctl status nginx.service --no-pager sudo systemctl reload nginx.service
sudo passenger-statusTo pick up new application code without dropping requests, use a Passenger restart:
sudo passenger-config restart-app /opt/passenger-demo/rubySecurity Recommendations
- Keep friendly error pages off. They are already off in this image, so application stack traces are never shown to clients.
- Add TLS by fronting nginx with Let's Encrypt and Certbot, and open
:443. - Restrict the NSG so
:80and:443are reachable only from your client networks if this is a private service. - Run apps as an unprivileged user. The demo apps run as
ppdemo. Keep your own apps off root. - Remove or replace the demo apps (
/opt/passenger-demo/) once you deploy your own application. - Patch the OS monthly with
sudo apt-get update && sudo apt-get upgrade && sudo reboot. - Do not enable Passenger Enterprise features. This image ships the open source edition only.
Support and Licensing
Phusion Passenger open source edition is licensed under the MIT License. There is no per-CPU or per-deployment fee.
SecureAnyCloud provides commercial support for this image, separately from the upstream project.
- Email: sales@secureanycloud.com
- Website: secureanycloud.com
- Support hours: 24/7 with a guaranteed 24 hour response SLA
Deploy on Azure
Launch Phusion Passenger on Ubuntu 24.04 with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Deploy on Azure
Launch Phusion Passenger on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Phusion Passenger (open source edition) is a mature, polyglot application server that serves Ruby, Node.js and Python web applications through nginx. It spawns and supervises your application processes, load balances requests across workers, automatically restarts crashed workers, and supports zero-downtime application restarts. passenger-status and passenger-memory-stats give you clear operational visibility.
This SecureAnyCloud AMI runs Passenger integrated with nginx on Ubuntu 24.04 on AWS. Passenger is an application server with no admin console or login, so there is nothing to authenticate to. Instead, the image ships two small demo apps, pre-deployed and served through Passenger, to prove that the runtime executes code on every request:
- a Ruby (Rack) app at
/that renders a live server timestamp and the worker PID - a Node.js (Express) app at
/node, running as a separate Passenger application group
Both apps render a live epoch and worker PID that change per request, so you can see Passenger executing real code rather than serving a static file.
What you get:
- Phusion Passenger 6.1 (open source edition, MIT licensed), integrated with nginx through the official Phusion APT repository (the
libnginx-mod-http-passengerdynamic module) - Ruby 3.2 (from the distribution) with the Rack gem, and Node.js 22 LTS with Express, so the polyglot runtime is real
- A Ruby (Rack) demo app at
/and a Node.js (Express) demo app at/node, each a distinct Passenger application group - A dedicated EBS application data volume mounted at
/opt/passenger-demo, so your app code lives on its own independently resizable disk - A
passenger-firstboot.servicesystemd oneshot that starts nginx, confirms that the demo app answers, resolves the instance public IP, and writes a non-secret endpoints notes file - Secure defaults:
passenger_friendly_error_pages off(no stack traces to clients),server_tokens off, and Passenger anonymous telemetry and security-update phone-home disabled - nginx on
:80as the only public entry point, with no admin login surface and no baked credential - An Ubuntu 24.04 LTS base with the latest security patches applied at build time, and the AWS SSM agent installed for Systems Manager integration
- 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA
Prerequisites
- An AWS account subscribed to the Phusion Passenger listing on AWS Marketplace
- An EC2 key pair, a VPC with a public subnet, and a security group that allows inbound TCP 22 (SSH) and TCP 80 (HTTP) from your client networks
- Recommended instance type:
m5.large(2 vCPU, 8 GB RAM) for development and light-to-moderate application workloads. For higher concurrency or CPU-bound apps, usem5.xlargeor larger.
Connecting to your instance
Each OS variant of this listing has its own default SSH login user. Use the entry that matches the AMI variant you launched.
- Ubuntu 24.04 LTS: log in as ubuntu, for example ssh -i your-key.pem ubuntu@<instance-public-ip>
Launch from the AWS Console
In the AWS Marketplace or the EC2 console, subscribe to the Phusion Passenger listing and choose Launch. Select an m5.large (or larger) instance type, your key pair, and a security group that allows:
- TCP 22 (SSH) from your management network
- TCP 80 (HTTP) from your client networks
Add TCP 443 if you plan to terminate TLS on the instance.
Launch from the AWS CLI
Replace the AMI ID, key name, security group and subnet with your own values, then run:
AMI_ID=<the-phusion-passenger-ami-id> aws ec2 run-instances \
--image-id "$AMI_ID" \
--instance-type m5.large \
--key-name your-key \
--security-group-ids sg-xxxxxxxx \
--subnet-id subnet-xxxxxxxx \
--associate-public-ip-address \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=passenger-01}]'Connect via SSH
Connect to the instance over SSH:
ssh -i your-key.pem ubuntu@<public-ip>nginx.service and passenger-firstboot.service start automatically on first boot. There is no admin account to set up, because Passenger has no login.
Verify Passenger and nginx
Check the Passenger version, the nginx service state and the listening port:
passenger-config --version sudo systemctl is-active nginx.service
sudo ss -tln | grep ':80 'Expected output: Passenger is present and nginx is listening on :80.
Phusion Passenger(R) 6.1.8 active LISTEN 0 511 0.0.0.0:80 0.0.0.0:* LISTEN 0 511 [::]:80 [::]:*You can also run Passenger's own install checker. It validates that the Passenger nginx module is wired up correctly:
printf '\n\n\n\n' | sudo passenger-config validate-installThe expected output ends with Everything looks good. :-).
* Checking whether this Passenger install is in PATH... ✓ * Checking whether there are no other Passenger installations... ✓ Everything looks good. :-)Request the Ruby (Rack) Demo App
Passenger has no admin UI, so the demo apps are how you confirm it works. Request the Ruby app at / twice in a row:
curl -s http://127.0.0.1/
curl -s http://127.0.0.1/Expected output: the epoch and Worker PID values prove that Passenger executes the app on every request.
<!doctype html><html><head><title>Phusion Passenger - Ruby demo</title></head><body><h1>Phusion Passenger (open source)</h1><p>Ruby 3.2.3 application served by Passenger + nginx.</p><p>Server time: 2026-07-22T01:48:45Z epoch=1784684925</p><p>Worker PID: 6902</p></body></html>The epoch value increases between calls. It is an in-process, per-request value that cannot come from a cached or static file. This is the work an application server does that a plain static web server cannot.
You can also open http://<instance-public-ip>/ in a browser.
Request the Node.js (Express) Demo App
The same image also serves a Node.js Express app at /node. It runs as a separate Passenger application group, so one server runs two languages and Passenger manages both. Request it:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/node
curl -s http://127.0.0.1/nodeExpected output:
HTTP 200 <!doctype html><html><head><title>Phusion Passenger - Node demo</title></head><body><h1>Phusion Passenger (open source)</h1><p>Node.js v22.23.1 application served by Passenger + nginx.</p><p>Server time: 2026-07-22T01:48:45.635Z epoch=1784684925</p><p>Worker PID: 6920</p></body></html>The Node.js worker has a different PID from the Ruby worker, because Passenger runs them as independent application processes.
Inspect Live Processes with passenger-status
passenger-status shows the application processes that Passenger manages. Warm both apps, then inspect them:
curl -s -o /dev/null http://127.0.0.1/
curl -s -o /dev/null http://127.0.0.1/node
sudo passenger-statusExpected output: two application groups, each with a live worker process.
Version : 6.1.8 Instance: xxxxxxxx (nginx/1.24.0 (Ubuntu) Phusion_Passenger/6.1.8) ----------- General information ----------- Max pool size : 6 App groups : 2 Processes : 2 Requests in top-level queue : 0 ----------- Application groups ----------- passenger-demo-node: App root: /opt/passenger-demo/node * PID: 6920 Sessions: 0 Processed: 3 Uptime: 0s passenger-demo-ruby: App root: /opt/passenger-demo/ruby * PID: 6902 Sessions: 0 Processed: 2 Uptime: 0sPassenger spawns these workers on demand and automatically restarts any that crash. If you kill a worker PID, the next request transparently spawns a replacement.
Check Memory Use and Endpoint Notes
passenger-memory-stats reports the memory used by the Passenger watchdog, the Passenger core and each application worker. Run it, then read the endpoint notes file:
sudo passenger-memory-stats
sudo cat /var/lib/sac/data/passenger-endpoints.notesExpected output: the notes file lists the demo URLs and where to deploy your own app. Passenger has no credentials to rotate.
----- Passenger processes ----- PID VMSize Private Name ------------------------------- 6833 359.8 MB 3.3 MB Passenger watchdog 6837 1035.5 MB 3.7 MB Passenger core 6902 228.8 MB 5.3 MB Passenger RubyApp: passenger-demo-ruby 6920 1031.9 MB 16.2 MB Passenger NodeApp: /opt/passenger-demo/node
# Phusion Passenger — Endpoint Notes PASSENGER_RUBY_DEMO_URL=http://<instance-public-ip>/ PASSENGER_NODE_DEMO_URL=http://<instance-public-ip>/node PASSENGER_APP_ROOT=/opt/passenger-demo INSPECT_PROCESSES=Run 'sudo passenger-status' to see live application process groups.Deploy Your Own App
Passenger serves any Ruby/Rack, Node.js or Python app. Your application tier lives on the dedicated EBS volume mounted at /opt/passenger-demo. Copy your app there:
scp -r -i your-key.pem ./myapp ubuntu@<public-ip>:/tmp/myapp ssh -i your-key.pem ubuntu@<public-ip> 'sudo mv /tmp/myapp /opt/passenger-demo/myapp && sudo chown -R ppdemo:ppdemo /opt/passenger-demo/myapp'Then point nginx at your app. For a Ruby/Rack app, set the server root to its public/ directory and add passenger_enabled on;. For a Node.js app, add a location block with passenger_app_type node; and passenger_startup_file app.js;.
The bundled /etc/nginx/sites-available/sac-passenger vhost is a working reference for both patterns. After editing, validate the configuration and reload nginx:
sudo nginx -t && sudo systemctl reload nginxRun these commands against your own app on your own instance.
Server Components
The image places these components at the following paths:
- Passenger nginx module config: /etc/nginx/conf.d/mod-http-passenger.conf
- nginx vhost: /etc/nginx/sites-available/sac-passenger
- Ruby (Rack) demo app: /opt/passenger-demo/ruby/config.ru
- Node.js (Express) demo app: /opt/passenger-demo/node/app.js
- Application data volume: /opt/passenger-demo (dedicated EBS volume)
- Application user: ppdemo (unprivileged system user)
- Logs: systemd journal (journalctl -u nginx.service) and /var/log/nginx/
- Firstboot script: /usr/local/sbin/passenger-firstboot.sh
- Firstboot service: /etc/systemd/system/passenger-firstboot.service
- Endpoint notes: /var/lib/sac/data/passenger-endpoints.notes (mode 0644)
- Firstboot sentinel: /var/lib/sac/data/passenger-firstboot.done
Managing Passenger and nginx
Passenger runs inside nginx, so managing the web server also manages the application server. Check the service, reload it, and inspect the processes:
sudo systemctl status nginx.service --no-pager sudo systemctl reload nginx.service
sudo passenger-statusTo pick up new application code without dropping requests, warm the app group and use a Passenger restart:
curl -s -o /dev/null http://127.0.0.1/
sudo passenger-config restart-app /opt/passenger-demo/rubySecurity Recommendations
- Keep friendly error pages off. They are already off in this image, so application stack traces are never shown to clients.
- Add TLS by fronting nginx with Let's Encrypt and Certbot and opening
:443, or terminate TLS at an Application Load Balancer with AWS Certificate Manager. - Restrict the security group so
:80and:443are reachable only from your client networks if this is a private service. - Run apps as an unprivileged user. The demo apps run as
ppdemo. Keep your own apps off root. - Remove or replace the demo apps (
/opt/passenger-demo/rubyand/opt/passenger-demo/node) once you deploy your own application. - Patch the OS monthly with
sudo apt-get update && sudo apt-get upgrade && sudo reboot. - Do not enable Passenger Enterprise features. This image ships the open source edition only.
Support and Licensing
Phusion Passenger open source edition is licensed under the MIT License. There is no per-CPU or per-deployment fee.
SecureAnyCloud provides commercial support for this image, separately from the upstream project.
- Email: sales@secureanycloud.com
- Website: secureanycloud.com
- Support hours: 24/7 with a guaranteed 24 hour response SLA
Deploy on AWS
Launch Phusion Passenger with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Deploy on AWS
Launch Phusion Passenger Application Server on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com