Deploying Dockerized Strapi on DigitalOcean App Platform

July 21, 2024

  • Tutorial
Thumbnail

I recently embarked on the journey of running a dockerized version of Strapi on the DigitalOcean App Platform. Here's a detailed walkthrough of my setup process, following the official documentation.

Quick Start with Strapi

First, I followed the Strapi Quick Start Guide to set up Strapi. This guide is a great starting point for getting a basic Strapi application up and running.

Dockerizing Strapi

Next, I dockerized the Strapi setup. The official Docker installation guide was invaluable for this step. Notably, I opted not to add the database service to the docker-compose.yml file. Instead, I configured the database separately on DigitalOcean.

Deploying to DigitalOcean App Platform

After setting up my Strapi application and dockerizing it, I pushed the repository to GitHub. Then, I deployed it on the DigitalOcean App Platform, again following the official documentation. Here, I paired the app with a Managed PostgreSQL Database from DigitalOcean.

Note that I skipped the part where you have to create separate ./config/env/production folder for production environment.

Environment Variables

App Environment Variables

Setting up the environment variables correctly on the DigitalOcean App Platform is crucial. Here are the variables I used:

NODE_ENV=production
APP_URL=${APP_URL}
DATABASE_CLIENT=postgres
DATABASE_HOST=${db.HOSTNAME}
DATABASE_PORT=${db.PORT}
DATABASE_NAME=${db.DATABASE}
DATABASE_USERNAME=${db.USERNAME}
DATABASE_PASSWORD=${db.PASSWORD}
DATABASE_SSL_REJECT_UNAUTHORIZED=false
DATABASE_SSL=true

Make sure to set DATABASE_SSL to true as DigitalOcean Database policy required incoming connections to be secured.

These variables ensure that Strapi connects to the PostgreSQL database correctly. I also set the component environment variables.

APP_KEYS="toBeModified1,toBeModified2"
API_TOKEN_SALT=tobemodified
ADMIN_JWT_SECRET=tobemodified
TRANSFER_TOKEN_SALT=tobemodified
JWT_SECRET=tobemodified
DATABASE_SSL_REJECT_UNAUTHORIZED=false

Make sure to replace the placeholders with your actual values.

After the build is successfully running, you can visit the App Platform link.

Successful Build
Live Demo

Note on Resource Requirements

Running Strapi and Docker may require at least 2GB of RAM to build successfully. To avoid any resource-related issues, I chose the $25/month plan, which provides 2 GB RAM, 1 vCPU, and 200 GB bandwidth.

Cost

Including Database as a Docker Service

If you prefer not to use DigitalOcean's managed PostgreSQL database, you can also include the database as a Docker service too. Follow the adjustments below.

Adding PostgreSQL Database Docker Service

Add strapiDB service to your docker-compose.yml file.

version: '3'
services:
  strapi:
    container_name: strapi
    build: .
    image: strapi:latest
    restart: unless-stopped
    env_file: .env
    environment:
      DATABASE_CLIENT: postgres
      DATABASE_HOST: ${DATABASE_HOST}
      DATABASE_PORT: ${DATABASE_PORT}
      DATABASE_NAME: ${DATABASE_NAME}
      DATABASE_USERNAME: ${DATABASE_USERNAME}
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      JWT_SECRET: ${JWT_SECRET}
      ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET}
      APP_KEYS: ${APP_KEYS}
      NODE_ENV: ${NODE_ENV}
    volumes:
      - ./config:/opt/app/config
      - ./src:/opt/app/src
      - ./package.json:/opt/package.json
      - ./yarn.lock:/opt/yarn.lock
      - ./.env:/opt/app/.env
      - ./public/uploads:/opt/app/public/uploads
    ports:
      - '1337:1337'
    networks:
      - strapi
    depends_on:
      - strapiDB

  strapiDB:
    container_name: strapiDB
    platform: linux/amd64 #for platform error on Apple M1 chips
    restart: unless-stopped
    env_file: .env
    image: postgres:12.0-alpine
    environment:
      POSTGRES_USER: ${DATABASE_USERNAME}
      POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
      POSTGRES_DB: ${DATABASE_NAME}
    volumes:
      - strapi-data:/var/lib/postgresql/data/ #using a volume
      - ./data:/var/lib/postgresql/data/ # if you want to use a bind folder
    ports:
      - '5432:5432'
    networks:
      - strapi

volumes:
  strapi-data:

networks:
  strapi:
    name: Strapi
    driver: bridge

In this configuration, Docker will bind the folder ./data to the local machine as well. So you'd want to ignore that folder inside your .gitignore file.

data/

Update .env

Next, you'd want to update your .env file.

HOST=0.0.0.0
PORT=1337
APP_KEYS="toBeModified1,toBeModified2"
API_TOKEN_SALT=tobemodified
ADMIN_JWT_SECRET=tobemodified
TRANSFER_TOKEN_SALT=tobemodified
JWT_SECRET=tobemodified

# Database
DATABASE_CLIENT=postgres
DATABASE_HOST=strapiDB
DATABASE_PORT=5432
DATABASE_NAME=strapi
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=strapi
DATABASE_POOL_MIN=0

Notice that I set DATABASE_POOL_MIN=0. This is important as Docker will kill any idle connections, making it impossible to keep any open connections to the database.

Adjust App Platform Resource Requirements

Running both the app and the db containers can be more resource heavy, you may need to increase the size of your application. While building this app, I encountered multiple Out of Memory errors. If you encounter this, you may have to increase the resource plan.

Repository

For reference, you can check out the repository I put together for this deployment here. For the included database, you can check it out under the branch database-included.

Deploying Dockerized Strapi on DigitalOcean App Platform was a smooth experience thanks to the comprehensive documentation provided by Strapi. With the right configuration and sufficient resources, you can get your Strapi application up and running in no time.