← Back to Guides
Profile image for Thomas Smyth

By Thomas Smyth

Published 14th June 2022

Deploy Payload to Northflank

Payload is a free open-source TypeScript headless CMS & application framework built with Express, MongoDB and React. This guide will show you how to create a new Payload project and deploy it on Northflank. The full source code used in this guide can be found in this Git repository.

Initiate the Payload Project

To start, we must initiate a new Payload project from Payload’s starter kit and push it to a Git repository on a Git provider linked to your Northflank account to allow Northflank to access it.

  1. Initiate a new Payload project by running npm init payload-app and inputting the information requested by the command line interface.

  2. Create a new file called .gitignore that contains the following:

    # Profile files
    .env
    
    # Dependencies
    node_modules/

Configure Payload

Before you can deploy Payload to a production environment, we must configure it via the /src/payload.config.ts file:

  1. Configure Payload to work with the correct hostname by setting serverURL to process.env.PAYLOAD_PUBLIC_BASE_DNS, as seen in the example below.

    • To ensure Payload continues to run locally for development purposes, add PAYLOAD_PUBLIC_BASE_DNS=http://localhost:3000 to your .env file. When you deploy Payload on Northflank you will need to set the Northflank domain or your own custom domain as an environment variable with this key, see deploy to Northflank.

  2. Configure Payload's rate limiter to work behind Northflank's load balancers by setting rateLimit.trustProxy to true, as seen in the example below.

    • By enabling this option Payload will rate limit requests based on the originating IP addresses of the requests to the Northflank load balancers. Without this option being enabled, all requests will appear as if they are originating from the Northflank load balancers and your users will get rate limited very quickly without cause.

    import { buildConfig } from 'payload/config';
    import path from 'path';
    // import Examples from './collections/Examples';
    import Users from './collections/Users';
    
    export default buildConfig({
     serverURL: process.env.PAYLOAD_PUBLIC_BASE_DNS,
     rateLimit: {
       trustProxy: true,
     },
     admin: {
       user: Users.slug,
     },
     collections: [
       Users,
       // Add Collections here
       // Examples,
     ],
     typescript: {
       outputFile: path.resolve(__dirname, 'payload-types.ts')
     },
    });

Configure Docker

To deploy your new project on Northflank, we must configure a Dockerfile that defines the environment the Payload app will run in.

  1. Create a new file called Dockerfile that contains the following:

    ARG NODE_VERSION=14
    
    # Setup the build container.
    FROM node:${NODE_VERSION}-alpine AS build
    
    WORKDIR /home/node
    
    # Install dependencies.
    COPY package*.json .
    
    RUN yarn install
    
    # Copy the source files.
    COPY src src
    COPY tsconfig.json .
    
    # Build the application.
    RUN yarn build && yarn cache clean
    
    # Setup the runtime container.
    FROM node:${NODE_VERSION}-alpine
    
    WORKDIR /home/node
    
    # Copy the built application.
    COPY --from=build /home/node /home/node
    
    # Expose the service's port.
    EXPOSE 3000
    
    # Run the service.
    CMD ["yarn", "run", "serve"]
  2. Commit and push your project to a Git repository on a Git provider linked to your Northflank account.

    • For more information on how to link a Git account to your Northflank account, check out our documentation.

Deploy to Northflank

Now we have initiated our Payload project, we can now deploy it to Northflank.

  1. Create a new combined service with the following configuration:

    1. Under repository, select the Git repository you pushed your project to.

    2. Under build options, select the Dockerfile build type.

      • Port 3000 will automatically be detected from the image manifest and will be exposed with the HTTP protocol.

    3. Under resources, it’s recommended to use plan nf-compute-50 or larger to ensure appropriate app performance.

    Deploy Payload to Northflank, Combined Service Creation

  2. Create a new MongoDB addon.

    • Choose the storage size according to your needs, it can be increased later if your storage needs change.

    Deploy Payload to Northflank, MongoDB Addon Creation

  3. Create a new secret group.

    1. Add the following keys and assign them the respective values.

      KeyValue
      PAYLOAD_PUBLIC_BASE_DNSThe unique code.run domain, found at the top right corner of your service, or the custom domain linked to your service prefixed with https://.
      PAYLOAD_SECRETA random secret.
      • To bring up a tool to generating random secrets, click the key symbol at the top right of the secrets section of the form.

    2. Link the MONGO_SRV variable from the MongoDB addon created in the previous step and assign it the alias MONGODB_URI.

    Deploy Payload to Northflank, Secret Group Creation

  4. Wait for your project to be built and deployed, if your project has already been deployed restart the service and wait for it to restart, then open the web interface by clicking on the link in the top right corner of your service.

  5. On the initial Payload page, you will be asked to create a user. Once you have created a user, you will be able to start creating content and data!

Enabling Uploads

If you wish to enable Payload's uploads feature on your deployment, you can configure your deployment to upload files to a persistent volume attached to your service, or an S3 bucket provided by a MinIO addon. I recommend the latter of these options as it will allow you to run multiple instances of your Payload service making your service scale better and be more resilient. Each of these options are documented in more detail below.

Enabling Uploads to a Persistent Volume

This section will show you how to enable uploads to a persistent volume. The full source code used in this section can be found in this Git repository.

  1. Set update in the appropriate collection to { staticURL: '/uploads', staticDir: '/uploads' }, as seen in the example below:

    import { CollectionConfig } from 'payload/types';
      
      // Example Collection - For reference only, this must be added to payload.config.ts to be used.
      const Examples: CollectionConfig = {
        slug: 'examples',
        upload: { staticURL: '/uploads', staticDir: '/uploads' },
        admin: {
          useAsTitle: 'someField',
        },
        fields: [
          {
            name: 'someField',
            type: 'text',
          },
        ],
      }
      
      export default Examples;
  2. Commit and push the change to your Git repository.

  3. In your combined service, navigate to "Volumes" and add a new volume with the container mount path /uploads.

    • Choose the storage size according to your needs, it can be increased later if your storage needs change.

    Deploy Payload to Northflank, Volume Creation

Enabling Uploads to a S3 bucket provided by a MinIO Addon

This section will show you how to enable uploads to a S3 bucket provided by a MinIO addon. The full source code used in this section can be found in this Git repository.

  1. Configure the Payload cloud storage plugin in the /src/payload.config.ts file, as seen in the example below:

    import { buildConfig } from 'payload/config';
    import { cloudStorage } from '@payloadcms/plugin-cloud-storage';
    import { s3Adapter } from '@payloadcms/plugin-cloud-storage/s3';
    import path from 'path';
    import Examples from './collections/Examples';
    import Users from './collections/Users';
    
    export default buildConfig({
       serverURL: process.env.PAYLOAD_PUBLIC_BASE_DNS,
       admin: {
          user: Users.slug,
       },
       collections: [
          Users,
          Examples,
       ],
       typescript: {
          outputFile: path.resolve(__dirname, 'payload-types.ts')
       },
       plugins: [
          // Pass the plugin to Payload
          cloudStorage({
             collections: {
                // Enable cloud storage for Examples collection
                examples: {
                   // Create the S3 adapter
                   adapter: s3Adapter({
                      config: {
                         endpoint: process.env.MINIO_ENDPOINT,
                         credentials: {
                            accessKeyId: process.env.MINIO_ACCESS_KEY,
                            secretAccessKey: process.env.MINIO_SECRET_KEY,
                         },
                         region: 'us-east-1',
                         forcePathStyle: true,
                      },
                      bucket: 'uploads',
                   }),
                },
             },
          }),
       ],
    });
    • In the example, we have enabled the examples collection and enabled uploads for it.

    • For more information on how to configure the Payload cloud storage plugin, check out their GitHub repository.

  2. Commit and push the change to your Git repository.

  3. Create a new MinIO addon.

    1. Enable the "Publicly accessible" option.

    2. Link the following variables to your secret group created in the earlier step and assign them the respective aliases.

      Variable nameAlias
      EXTERNAL_MINIO_ENDPOINTMINIO_ENDPOINT
      ACCESS_KEYMINIO_ACCESS_KEY
      SECRET_KEYMINIO_SECRET_KEY
      • Choose the storage size according to your needs, it can be increased later if your storage needs change.

    3. Create a bucket in your MinIO addon named uploads, you can do this with the MinIO Client by running EXTERNAL_MINIO_CONNECT_COMMAND command found in your addon's connection details and then mc mb <addon name>/uploads.

    Deploy Payload to Northflank, MinIO Addon Creation

  4. Restart your combined service.

If you encounter any issues while following this guide we're happy to assist you with your Payload deployment at support@northflank.com. At Northflank we also have dedicated support plans for business customers.

Common issues

  • ERROR (payload): Forbidden: You are not allowed to perform this action.

This error usually occurs because serverUrl has not been configured correctly. To resolve:

  1. Check serverUrl is set in your application's buildConfig to process.env.PAYLOAD_PUBLIC_BASE_DNS
  2. Ensure your application is receiving the environment variable PAYLOAD_PUBLIC_BASE_DNS, the value should be the full domain name you are using to access the application, including the https:// prefix. You can run the command printenv | grep PAYLOAD_PUBLIC_BASE_DNS in the shell of a running container to check it exists in your runtime environment.

See the configure payload and deploy to Northflank for detailed instructions.

Using Northflank to deploy Payload with MongoDB

Northflank allows you to deploy your code and databases within minutes. Sign up for a Northflank account and create a free project to get started.

  • Multiple read and write replicas
  • Observe & monitor with real-time metrics & logs
  • Low latency and high performance
  • Backup, restore and fork databases
  • Private and optional public load balancing as well as Northflank local proxy

Share this article with your network