[Next.js + Strapi] Deploy my portfolio website to Vercel and Digital Ocean

Background

Once we have built our application locally, now let’s deploy it to make it public.

In this post, I would like to walk you through the process of deploying front end (Next.js application) to Vercel and back end (Strapi v4 application) to Digital Ocean (DO) separately on for my personal site.

PART I: Deploy Front End (Next.js app) to Vercel

Choose Vercel as a hosting service of our Next.js app

Compared to DigitalOcean, Vercel is pretty straightforward to deploy the Next.js app (Vercel is also the creator of Next.js). So why not Vercel?

Steps to deploy Next.js app to Vercel

First connect code repo (from github, for instance) to Vercel, and following the instructions step by step.

Choose the code source

If necessary (depends your own application), you can set the env variables values in hosting environment as well as configure your own custom domain name.

PART II: Deploy Backend (Strapi V4 app) to Digital Ocean

DigitalOcean (DO) is a relatively new cloud provider that has simplified the deployment of cloud applications.

Config database for production environment

Step 1: Underconfig fold, create a env folder and then a production folder inside. Create a file called database.js (config/env/production/database.js)

Explanation: The Strapi will use this file as the configuration file whenever the Node environment is set to production. And this new database.js will override the top level one (/config/database.js).

sqliteis by default used for local environment, but postgres will be used for production environment.

We will override the env variables in our DigitalOcean environment — DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USERNAME, DATABASE_PASSWORD, DATABASE_CA.

Step 2: We need to install a npm module (npm install pg) to allow Postgres client to work with our Postgres database so our Strapi app can communicate with the database.

Step 3: Finally, commit all the code to Github repo.

Step 4: Start deploying our application to DigitalOcean

Inside your DigitalOcean Control Panel, click Create button on the top corner and click Apps:

Select GitHub and select your reposiotry and branch you want to deploy.

Click Next button.

Set the HTTP Port to 1337 since Strapi use this one while leaving the Build Command and Run Command as unchanged.

Leave default ‘db’ as database. Now we have PostgreSQL database setup for production environment.

Config env variables values in DigitalOcean.

APP_KEYS, JWT_SECRET, API_TOKEN_SALF

While our application is being built, we should set those env variables inside Settings otherwise the deployment process will throw errors.

Also set NODE_ENV to be production otherwise our Strapi app won’t work correctly as it’s supposed to do.

Once it’s done with deployment. we will see our live app:

Open our admin panel of our deployed Strapi app:

Login and then create content from Strapi Dashboard.

Store the media files (images, videos, etc.) in DigitalOcean Space

Up to now, I can create text context (such as writing post) inside Strapi Dashboard’s Content Manager, but the images I have uploaded to the Media Library are gone!!!

The media Library of Strapi app in production env

The reason for that is because the Strapi Media Library itself doesn’t store my media files on production environment, I need to find a place to store and manage these large files especially like media files. And the choice goes to DigitalOcean Spaces.

Q: Why do I have to store image files in external storage instead of DigitalOcean app platform which serves my backend code?

Answer: Because there is no feasible way of serving media files “directly” from Strapi App on DigitalOcean App Platform. The App Platform uses “ephemeral file system”, just like Heroku. And whereas it is possible to cram your static files as part of the application’s slug, the media files need to be served from outside location (such as DigitalOcean Spaces).

DigitalOcean Spaces (DO Spaces) is one of the several products offered by DO. DO is S3-Compatible Cloud Object Storage in the cloud that helps you store files in the cloud and provides an instant, high availability storage that can provide practically infinite scale.

The price for Digital Ocean Space looks friendly: $5 /month for unlimited spaces.

monthly price for DO space: $5

DigitalOcean Spaces is a great, low-cost cloud storage for large objects like high-quality images. Despite that, it has some drawbacks -

  1. Spaces cannot optimize your images to the correct format like WebP or the even newer AVIF.
  2. It cannot compress your images and make them suitable for delivery on the web.
  3. It does not offer real-time image transformations on images, which means you will have to resize the images for every screen size on your own.

Connect Strapi V4 to DigitalOcean Spaces via strapi-provider-upload-do

$ npm i strapi-provider-upload-dos

I initially created ./config/plugins.js or ./config/env/production/plugins.jswith below content:

module.exports = ({ env }) => ({
// ...
upload: {
config: {
provider: "strapi-provider-upload-dos",
providerOptions: {
key: process.env.DO_SPACE_ACCESS_KEY,
secret: process.env.DO_SPACE_SECRET_KEY,
endpoint: process.env.DO_SPACE_ENDPOINT,
space: process.env.DO_SPACE_BUCKET,
directory: "media", // optional
},
},
},
// ...
});

Add the below to .env

DO_SPACE_ACCESS_KEY=
DO_SPACE_SECRET_KEY=
DO_SPACE_ENDPOINT=
DO_SPACE_BUCKET=
DO_SPACE_DIRECTORY=
DO_SPACE_CDN=

(source: https://forum.strapi.io/t/upload-media-to-digitalocean-spaces-using-strapi-v4/16135)

!!But there is an Issue about the setup of the upload provider for DO Spaces

Same issue was posted in here:

Solution

  • Store env variables such as DO_SPACE_ACCESS_KEY in Digital Ocean App-Level Environment Variables or (possibly component-level environment variables):
  • And change the above config code to be the below:
module.exports = ({ env }) => ({
upload: {
config: {
provider: "strapi-provider-upload-dos",
providerOptions: {
// key: process.env.DO_SPACE_ACCESS_KEY,
// secret: process.env.DO_SPACE_SECRET_KEY,
// endpoint: process.env.DO_SPACE_ENDPOINT,
// space: process.env.DO_SPACE_BUCKET,
// directory: process.env.DO_SPACE_DIRECTORY,
// cdn: process.env.DO_SPACE_CDN,
key: env("DO_SPACE_ACCESS_KEY"),
secret: env("DO_SPACE_SECRET_KEY"),
endpoint: env("DO_SPACE_ENDPOINT"),
space: env("DO_SPACE_BUCKET"),
},
},
},
});
  • You also need to config /config/env/production/middlewares.js or just /config/middlewares.js as below in order to see the preview of images in the Media Library of Strapi Admin panel:
module.exports = ({ env }) => [
"strapi::errors",
"strapi::cors",
"strapi::poweredBy",
"strapi::logger",
"strapi::query",
"strapi::body",
"strapi::favicon",
"strapi::public",
{
name: "strapi::security",
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
"connect-src": ["'self'", "https:"],
"img-src": [
"'self'",
"data:",
"blob:",
`${env("DO_SPACE_BUCKET")}.${env("DO_SPACE_ENDPOINT")}`,
],
"media-src": [
"'self'",
"data:",
"blob:",
`${env("DO_SPACE_BUCKET")}.${env("DO_SPACE_ENDPOINT")}`,
],
upgradeInsecureRequests: null,
},
},
},
},
];
  • Then commit your change to trigger the build & deployment process on DO. Once the deployment succeeds, upload media files (like photos) through the Media Library on your Strapi Admin panel in production environment (via your production Strapi app URL).
You need to config the middlewares.js

And then you will see the uploaded files in DO Spaces.

Fixing 404 error

Not finished yet!

In our Next.js app, a404 error was thrown when we trying to access the images stored inside the DO Spaces.

For example:

https://www.amyjuanli.com/_next/image?url=https://xxxxxx.nyc3.digitaloceanspaces.com/xxxxxxxx.png

To fix this, I add the image domain (DO Spaces) to next.config.js with below content:

const nextConfig = {
reactStrictMode: true,
images: {
loader: "default",
domains: ["xxxx.nyc3.digitaloceanspaces.com"],// replace the space name (or bucket name) with yours.
},
};
module.exports = nextConfig;

Then commit your changes and let’s Vercel re-build and re-deploy your front end app. Now go to your website (production url, such as my site https://www.amyjuanli.com) and refresh page, you will see the images are loaded successfully.

Summary

You could deploy Next.js to Digital Ocean as well. It’s just my personal preference to choose Vercel simply because it is the creator of Next.js. It cannot be wrong. 😄 As you see, I did have some struggles as it’s our first time to deploy some backend service to DigitalOcean and choose DigitalOcean Spaces as storage management system given tons of photos required in my personal portfolio website.

Please leave a comment if you have any questions. I would love to provide any valuable experience with you as much as possible.

🍀 Wish you the best luck!

--

--

Get the Medium app