cover-img

How to deploy PayloadCMS to Digitialocean and connect to S3 bucket

21 November, 2022

8

8

1

Contributors

In this article I will be going through the steps I took to set up PayloadCMS on Digitalocean along with cloud storage via S3 Bucket. I will not be going through specific configurations for PayloadCMS outside of the deployment process. I will instead refer to their documentation.
The deployment process is based on the articles provided here. If you are looking to get a head start, you can follow those articles and use this article as reference if you get stuck.

Step 1 - Create droplet.

Register an account on Digitalocean and create a droplet.
img
You can customise size, OS and authentication method to your preference. To keep it simple I'll be proceeding with the Digitalocean plan visible on the screenshot above along with Ubuntu as my OS and password authentication.

Step 1.2 - Initial server setup.

Once you have created your droplet, it's time to connect via SSH to add an admin user and set up a basic firewall. You can find your public IP if you click on the project where you installed your droplet.

Step 1.3 - Add an admin user.

Connect to your droplet as root user via SSH by using the command line on your system and type in the following
Next we will create an admin user
Lastly we will grant the user administrative privileges

Step 1.4 - Set up a basic firewall.

First we need to allow SSH connection through our firewall in order to log back in with our newly created user.
Then we can enable the firewall by typing in -
Now you should be able to SSH in to your droplet using the new user that you've just created with the firewall up and running. You can also check the status of the firewall by typing -

Step 2 - Change nameservers.

If you are looking to deploy to a specific domain you need to change your nameserver to point to Digitalocean. My domain was registered on Namecheap and I changed from Namecheap BasicDNS to Custom DNS and added the following nameservers
Digitalocean has documentation for various domain providers. If you are using a different domain register you can have a look at their documentation

Step 3 - Add your domain to the Networking tab.

Navigate to the Networking tab on your Digitalocean dashboard and add your domain. Then add two A records. One for root and the other for www.

Step 4 - Install Nginx.

To install Nginx and to make sure your existing packages are up to date, run the following in your droplet via the command line on your system that is connected through SSH -
Later down the line, we will be setting up Nginx in order to allow access via HTTP/HTTPS protocol. To do this we can run the following -
If everything is set up correctly you should now be able to access your Nginx installation via your public IP that you got from Step 1.

Step 4.1 - Set up server block.

When using the Nginx web server, server blocks (similar to virtual hosts in Apache) can be used to encapsulate configuration details and host more than one domain from a single server.

In order for us to serve our own custom domain we can set up a simple index.html file within the /var/www directory -
Next we will assign ownership and set administrative permission -
Then we will create the index.html page
You can use the following sample code taken from Digitalocean

Save and close the file by pressing Ctrl+X to exit, then when prompted to save, Y and then Enter.

We will set up a reverse proxy later on to replace the index.html with our PayloadCMS instance but for now we'll keep the index.html to make sure that we are able to access everything correctly over HTTP/HTTPS.
Next we will set up a configuration file for our domain directive -
Use the following sample that was taken from Digitalocean -
Next we will create a link to the sites-enabled directory

To avoid a possible hash bucket memory problem that can arise from adding additional server names, it is necessary to adjust a single value in the /etc/nginx/nginx.conf file. Open the file:

Find the server_names_hash_bucket_size directive and remove the # symbol to uncomment the line. If you are using nano, you can quickly search for words in the file by pressing CTRL and w.

Finally we can test for errors by running -
If no errors occurred, proceed to restart Nginx -

Step 4.2 - Secure Nginx with Let's encrypt.

Start by installing Certbot -

Certbot provides a variety of ways to obtain SSL certificates through plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary. To use this plugin, type the following:

Let’s Encrypt’s certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. The certbot package we installed takes care of this for us by adding a systemd timer that will run twice a day and automatically renew any certificate that’s within thirty days of expiration.

You can query the status of the timer with systemctl:

To test the renewal process run -

If you see no errors, you’re all set. When necessary, Certbot will renew your certificates and reload Nginx to pick up the changes. If the automated renewal process ever fails, Let’s Encrypt will send a message to the email you specified, warning you when your certificate is about to expire.

At this point you should be able to view your rendered index.html via your domain.

Step 5 - Connect to MongoDB.

You can either install your own instance inside your droplet our let a DBMS like MongoDB Atlas take care of it

Step 6 - Setting up cloud storage with S3 bucket.

Before we proceed to set up Node and clone our project into our droplet, we first need to configure our current file storage. If you're using the upload API on any of your fields, we need to connect those uploads to a persistent filesystem. In this article we'll be proceeding with S3 bucket.
If you don't already have an account, make sure to head over to AWS and create an account. I plan on keeping my files publically accessible and won't be covering access control. If that's something you plan on using then I suggest going over AWS S3 policy and reading up on how PayloadCMS handles access control over on their documentation

Step 6.1 - Generating access keys via AWS IAM.

If you're using AWS for the first time your IAM management console will have 0 users. Add a new user with access type Access key. Then give the AmazonS3FullAccess policy to the user.
Once you've completed the registration process, copy the access and secret keys and store them in your .env file within your project directory.

Step 6.2 - Add a bucket policy (Optional)

Follow this guide if you're planning to have your file publicly accessible.

Step 6.3 - Install & set up payloadcms/plugin-cloud-storage

Run npm install @payloadcms/plugin-cloud-storage to install the package and configure your payload.config.ts according to your own preferences. Here's my setup for reference -

Step 6.4 - disableLocalStorage.

Here's what my Media collection looks like -
You can customise your Media collection to your own liking, just make sure you disable local storage since you're going to be using S3 bucket in production.

Step 7 - Create a repository on Github.

Push your project files to Github in order to clone the project into your droplet.

Step 8 - Set up Node for production.

Navigate into your home directory in your droplet and fetch the installation by running -
Once that's done run -
Then proceed to install the Node package
To check if your installation was successful you can run
If NPM didn't get installed you can install it manually -
Next we'll clone our repository from github using git clone your_repository_url.
Then cd into your repo and install all the dependencies for your project by running npm install.
After all of the packages have been installed you can run npm run dev to start up a development session on http://localhost:your_project_port/admin. This session isn't publically accessible however if you open up another terminal and connect to your droplet via SSH, you should be able to connect to your development session using curl -

Step 9 - Install & configure PM2

PM2 makes it possible to daemonize applications so that they will run in the background as a service.

We can use NPM to install PM2
Then proceed to reboot the system
Inside your payload.config.ts make sure to change your URL endpoint
In order to serve our project in the background using PM2 we first need to build our PayloadCMS application by running npm run build. If you get stuck, have a look at your package.json file and make sure the scripts are configured correctly. Here's mine for reference -
After building our application we can start a background process using PM2 and provide the serve command for our application -

Applications that are running under PM2 will be restarted automatically if the application crashes or is killed, but we can take an additional step to get the application to launch on system startup using the startup subcommand.

As an additional step, we can save the PM2 process list and corresponding environments:

Start the service with systemctl:

If at this point you encounter an error, you may need to reboot, which you can achieve with sudo reboot.

Check the status of the systemd unit:

If you happen to get stuck, have a loot at their documentation

Step 10 - Set up reverse proxy

At this point our application is still running locally within our droplet. In order to make it publicly accessible we need to configure our Nginx server. In step 4.1 we created a server block for our domain. We need to make some additional configuration to our domain server -

Within the server block, you should have an existing location / block. Replace the contents of that block with the following configuration.

Replace 3000 with your own port and restart the Nginx server

Step 10.2 - Adjust upload file size

Navigate to Nginx config file -
Add the following inside the HTTP {} block
I'm setting the limit at 5 MB but you can set the limit according to your own setup

Thanks for reading. If you enjoyed this article make sure to leave a like and feel free to share your thoughts down below in the comment section. Let's connect!

headless

s3

develevate

howto

digitalocean

8

8

1

headless

s3

develevate

howto

digitalocean

More Articles

Showwcase is a professional tech network with over 0 users from over 150 countries. We assist tech professionals in showcasing their unique skills through dedicated profiles and connect them with top global companies for career opportunities.

© Copyright 2025. Showcase Creators Inc. All rights reserved.