Agency Logo

Deploying PayloadCMS app to CloudPanel

Estimated Time: 45-60 minutes
Last Updated: December 2024

Introduction

PayloadCMS is a powerful headless CMS that gives developers the flexibility they need while providing a great editorial experience. In this guide, we’ll walk through the process of deploying a PayloadCMS application to CloudPanel, ensuring your content management system is secure, scalable, and properly configured.

Prerequisites

Before we begin, make sure you have:

  • A VPS with CloudPanel installed (Version 2.0 or higher)
  • Basic familiarity with Linux and command line operations
  • A PayloadCMS project ready for deployment (This tutorial uses Payload v3.0)
  • Git installed
  • Node.js (Version 20.x or higher recommended)

Ready? Let’s dive in!

Step 1: Creating a CloudPanel site

Before we get started deploying our project, we need to create our CloudPanel site, which will automatically create an SSH user. We will then use this user to SSH into our VPS and execute the commands needed to deploy our app.

  1. Log in to your CloudPanel dashboard
  2. Create a new site:
    • Click “Sites” → “Add Site”
    • Select “Create a Node.js Site”
    • Enter your domain name and a port your application is running on (by default, PayloadCMS app runs on port 3000)
    • Choose your preferred Node.js version (version 20 or above recommended)
    • Remember the SSH password for the new user

Step 2: Database Configuration

If you are familiar with CloudPanel, you’ll know that there are 2 options for a database driver: MySQL and MariaDB. This is fine for most apps, especially WordPress, since it allows us to create databases straight from the panel interface.

Unfortunately, PayloadCMS currently only comes with support for MongoDB, PostgreSQL and SQLite. This means that we will either have to use 3rd party services (like MongoDB Atlas, Supabase etc.), or we will have to manually install database drivers to our VPS.

Since I personally prefer to have all my data owned by myself, I opted for the local DB installation. Plus, using a 3rd party database service would defeat the whole purpose of self-hosting a Payload app – I’d instead use a platform such as Vercel for that.

To get started installing and creating initial databases for our app, we need to SSH into our VPS as a root user. It’s not possible to install packages as a site user.

ssh root@<your-vps-address>

After logging in as root, we need to install a DB driver that we want to use. I prefer relational databases so I opted for PostgreSQL.

apt install postgresql

Once the installation finished, we need to start and enable the postgresql service, so it starts automatically even if our VPS restarts.

service postgresql enable
service postgresql start

Now that we have started PostgreSQL driver successfully, we have to create our database.

First, we have to switch to the newly created postgres user, as that’s the user that has the ability to create and modify databases.

su - postgres

Once we have switched our user, we have to enter psql, which is a terminal-based front-end to PostgreSQL.

psql

Now that we are in psql-mode, we have full permissions and ability to create and modify databases however we want and like.

For our app, we first need to create a user and set a password – that will be the user that will be able to modify our database.

CREATE USER payload WITH PASSWORD 'payload-db-pass';

After that, we create our database and make our user the owner of the database – this provides it with the ability to modify said database and the schema::

CREATE DATABASE payload_db;
ALTER DATABASE payload_db OWNER TO payload;
GRANT ALL PRIVILEGES ON DATABASE payload_db TO payload;

If you receive an error along the lines of “permission denied for schema public” upon running your app, run the following command as well:

GRANT ALL ON SCHEMA public TO payload; 

Step 3: Deploying Your Application

After starting our database driver and creating our database that will be used for the app, it’s time to deploy the app itself.

To get started, log into your VPS as a site user that was created upon the creation of a site.

ssh <your-user>@<your-vps-address>

After logging in as your user, we need to upload the application files to our app’s root directory. Root directory can be found inside the Cloudpanel area:

Switch to the directory:

cd /home/<site-user>/htdocs/<site-domain>

The easiest way to upload our application files is by cloning the Github repo:

git clone https://github.com/your_username/your-repo.git .

Next, let’s simply list the files in the directory to make sure our app was cloned successfully.

ls -la

Voila – our files are now right here, on our VPS. Now it’s just a simple case of installing dependencies, building and starting our app.

However, prior to building an app, we have to setup our ENV variables. Those include our database URI, the secret string Payload uses to encrypt and decrypt JWT tokens and the public app URL, which is used to configure CORS, format links and more. To do that, copy the example .env file:

cp .env.example .env

And then enter your variables:

nano .env
DATABASE_URI=postgresql://<user>:<password>@127.0.0.1:5432/db-name
PAYLOAD_SECRET=YOUR_SECRET_HERE
NEXT_PUBLIC_SERVER_URL=https://yourdomain.com

Next up, we have to install all dependencies of our app, which can be done via package manager of your choosing. For simplicity, we’re using npm, but yarn & pnpm are also viable options – you’ll just have to install them first:

npm install

After installing the dependencies, we have to build our app for production:

npm run build

Once our app is built for production, we simply have to start our server:

npm run start

If everything went successfully, you will see this message in your terminal:

That is extremely good sign – this means our app is working correctly. Remember, earlier on we created a Node.js app and specified port 3000 – that’s the port that our app is using, so we should now be able to simply visit our domain to view the app.

Our app is now live for the entire internet to see. However, you may have noticed a small problem – we can’t use our terminal anymore without closing the app. This is not something that’s going to work, so let’s fix that.

This can be fixed by install pm2, which is a daemon process manager that will help you manage and keep your application online 24/7. We have to install it via npm:

npm install --global pm2

Then, simply run the following command to start pm2 (make sure you replace the app name with your own):

pm2 start npm --name "<your-app-name>" -- start

This will keep our application up and running 24/7 (of course, unless our entire VPS goes down).

Common Issues and Troubleshooting

  • Database Connection Issues: Ensure your database URI includes the correct credentials and database name
  • 502 Bad Gateway: Check if your Node.js application is running and listening on the correct port
  • File Permission Errors: Make sure your application files have the correct ownership and permissions, even though they should be fine by default.
  • Build Failures: Verify all dependencies are properly installed and Node.js version is compatible

Maintenance and Updates

To update your application:

git pull origin main
npm install
npm run build
pm2 restart <app>

Make sure you perform regular maintenance tasks:

  • Monitor logs: pm2 logs <your-app-name>
  • Check system resources: pm2 monit
  • Update SSL certificates: They auto-renew, but verify expiration dates

Conclusion

You now have a production-ready PayloadCMS instance running on CloudPanel. Remember to monitor your application’s performance, keep dependencies updated, and maintain regular backups of your data.

Additional Resources

Ready to unlock the full potential of your business?