Deploy Angular Universal App to Shared Apache Hosting (With Passenger)

/ March 15, 2022/ Angular

(Last Updated On: March 15, 2022)
Ad:

If we search for “How to deploy Angular Universal to production” or “How to deploy Angular Universal to server”, we will find a lot of examples of one of two scenarios:

  1. Use Angular Universal’s Prerender to deploy an static website.
  2. Deploy an Angular Universal App to a VPS or a nginx server.

The thing is, most of us that already have some kind of website, already have a hosting provider, and most likely, it is an Apache-based shared hosting.

The cool thing is that Apache-based hostings have the ability to deploy Node (and another web) apps in a couple of clicks using Passenger, the not-so-cool thing is that an Angular Universal production build does not work out of the box there, and according to several people, it just plain not work.

In this post, I will write a step-by-step guide on how to deploy your Angular Universal App in a painless way. It will just take 10 minutes! (well maybe 20).

Step 1: Create an Node App on cPanel.

Ad:

On your hosting cPanel’s search bar write: “node.js”. You should find a “Setup Node.js App” option there. If not, then your hosting does not have Passenger installed and you can not host node apps there 😢

Inside there, click Create Application. Here just fill the Application root, and choose the Application URL.

After this is done, Passenger will generate an app.js, and a .htaccess file inside the Application root folder. Click on Start app and in your browser, navigate to the Application URL. You should see a message like this:

It works!

NodeJS 14.18.3

Step 2: Build your Angular Universal app.

Ad:

By default, our Angular Universal app server runs on port 4000, but, our Apache/Passenger host serves our site in port 80 for HTTP and port 443 for HTTPS. Since we are on shared hosting, there is no control over the server settings. This means we can not do any kind of port mapping or reverse proxy.

If you are like me, you are thinking “OK, then I will change the Angular port”. Sadly this will just produce an EACCESS error saying that you do not have permission to use that port(s).

Luckily, a post on the plesk board gave us the fix for this problem: we do not need to set any port, Passenger will take care of passing the server request to your node app.

Another problem we will face is that the run() function inside server.ts will not be called in our server because it is wrapped in an if statement that is never true. I have already created a pull request to fix this on the Universal repo. For now let’s us fix it locally.

Changing server.ts

Replace this:

function run(): void {
  const port = process.env['PORT'] || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

With this:

function isRunningOnApachePassenger(): boolean {
  return moduleFilename.includes('lsnode.js');
}

function run(): void {
  // Start up the Node server
  const server = app();

  if (isRunningOnApachePassenger()) {
    server.listen(() => {
      console.log('Node Express listening to Passenger Apache');
    });
    return;
  }

  const port = process.env['PORT'] || 4000;

  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

and this:

if (
  moduleFilename === __filename ||
  moduleFilename.includes('iisnode')
)

with this:

if (
  moduleFilename === __filename ||
  moduleFilename.includes('iisnode') ||
  isRunningOnApachePassenger()
)

Build your project

npm run build:ssr

This will leave you with this folder structure

dist
  /your-app-name
    /browser
    /server
dist is the folder that we will upload later to our hosting.

Step 3: Upload your files

Ad:

Since we do not want to complicate our lives, we will upload all the dist folders to our host inside the Application root folder from Step 1.

We should have something like this at the end:

server/path/to/your/application-root
  /dist
    /your-app-name
      /browser
      /server

Final step, update your Node.js app in cPanel

We have to change the Application startup file value inside our App config in cPanel, which currently is app.js to:

dist/your-app-name/server/main.js

Now, click on Restart and that is all! 🚀

I did this to successfully deploy the (for now hidden) future website of MascotasJesusMaria.com, my brother’s website about pets in Perú 🐱🐶.

Spread the love
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments