Deploying a Node.js app on an AWS production server
with Passenger in Apache mode on Debian 9 (with APT)
On this page you will learn how you can deploy your app to a server that is running Passenger. You can either follow these instructions with your own app, or you can use the sample Connect.js app we prepared.
Table of contents
1 Transferring the app code to the server
1.1 Push your code to a Git repository
We want to transfer our application's code to the server. The easiest way to do that is via Git.
If you have already setup a Git repository, push your application's code to that repository by running this on your local computer:
$ git push
If you have not already setup a Git repository, go to Github, create a repository and push your application's code there.
1.2 Login to your server, create a user for the app
Login to your server with SSH:
$ ssh -i your_ec2_key.pem email@example.com
adminuser with the name of an account with administrator privileges or sudo privileges.
This is usually
Now that you have logged in, you should create an operating system user account for your app. For security reasons, it is a good idea to run each app under its own user account, in order to limit the damage that security vulnerabilities in the app can do. Passenger will automatically run your app under this user account as part of its user account sandboxing feature.
You should give the user account the same name as your app. But for demonstration purposes, this tutorial names the user account
$ sudo adduser myappuser
We also ensure that that user has your SSH key installed:
$ sudo mkdir -p ~myappuser/.ssh $ touch $HOME/.ssh/authorized_keys $ sudo sh -c "cat $HOME/.ssh/authorized_keys >> ~myappuser/.ssh/authorized_keys" $ sudo chown -R myappuser: ~myappuser/.ssh $ sudo chmod 700 ~myappuser/.ssh $ sudo sh -c "chmod 600 ~myappuser/.ssh/*"
1.3 Install Git on the server
$ sudo apt-get install -y git
1.4 Pull code
You need to pick a location in which to permanently store your application's code. A good location is
/var/www/APP_NAME. Let us create that directory.
$ sudo mkdir -p /var/www/myapp $ sudo chown myappuser: /var/www/myapp
myappuser with your app's name and your app user account's name.
Now let us pull the code from Git:
$ cd /var/www/myapp $ sudo -u myappuser -H git clone git://github.com/username/myapp.git code
If you are using our sample app, use this Git clone command instead:
$ cd /var/www/myapp $ sudo -u myappuser -H git clone --branch=master https://github.com/phusion/passenger-nodejs-connect-demo.git code
Your app's code now lives on the server at
2 Preparing the app's environment
2.1 Login as the app's user
All subsequent instructions must be run under the application's user account. While logged into your server, login under the application's user account as follows:
$ sudo -u myappuser -H bash -l
2.2 Install app dependencies
Your application has various dependencies.
npm install in your app's directory:
$ cd /var/www/myapp/code $ npm install --production
Your app may also depend on services, such as PostgreSQL, Redis, etc. Installing services that your app depends on is outside of this tutorial's scope.
3 Configuring Apache and Passenger
Now that you are done with transferring your app's code to the server and setting up an environment for your app, it is time to configure Apache so that Passenger knows how to serve your app.
3.1 Go back to the admin account
You have previously logged into your app's user account in order to prepare the app's environment. That user does not have sudo access. In the next steps, you need to edit configuration files, for which sudo access is needed. So you need to switch back to the admin account.
This can be done by simply exiting the shell that was logged into the app's user account. You will then be dropped back to the admin account. For example:
# This is what you previously ran: admin$ sudo -u myappuser -H bash -l myappuser$ ... # Type `exit` to go back to the account you were before myappuser$ exit admin$ _
3.2 Edit Apache configuration file
We need to create an Apache configuration file and setup a virtual host entry that points to your app. This virtual host entry tells Apache (and Passenger) where your app is located.
$ sudo nano /etc/apache2/sites-enabled/myapp.conf
myapp with your app's name.
Put this inside the file:
<VirtualHost *:80> ServerName yourserver.com # Tell Apache and Passenger where your app's code directory is DocumentRoot /var/www/myapp/code/public PassengerAppRoot /var/www/myapp/code # Tell Passenger that your app is a Node.js app PassengerAppType node PassengerStartupFile app.js # Relax Apache security settings <Directory /var/www/myapp/code/public> Allow from all Options -MultiViews # Uncomment this if you're on Apache >= 2.4: #Require all granted </Directory> </VirtualHost>
yourserver.com with your server's host name, replace
/var/www/myapp/code with your application's code directory path and replace
app.js with your app's entry point file.
When you are done, restart Apache:
$ sudo apache2ctl restart
3.3 Test drive
You should now be able to access your app through the server's host name! Try running this from your local computer. Replace
yourserver.com with your server's hostname, exactly as it appears in the Apache config file's
$ curl http://yourserver.com/ ...your app's front page HTML...
If you do not see your app's front page HTML, then these are the most likely causes:
- You did not correctly configure your
ServerNamedirective. The ServerName must exactly match the host name in the URL. For example, if you use the command
curl http://188.8.131.52/to access your app, then the ServerName must be
- You did not setup DNS records. Setting up DNS is outside the scope of this tutorial. In the mean time, we recommend that you use your server's IP address as the server name.
Congratulations, you have successfully deployed your app!Continue: Deploying updates »