Deploying Next.js with Docker and Github actions to Digital Ocean
•code
Here comes another post about Github actions and deployment to Digital Ocean. This is from this site which is deployed with exactly this manner.
Why don't just go with Vercel?
It's a valid question and I have done in this way because
- Want to learn and get a better understanding of Github Actions
- Want to learn Docker
- I/We have most of our sites on Digital Ocean
Dockerfile
With this config you build multi stage environment, but in my case I only do it with production.
Dockerfile
# Source: https://github.com/vercel/next.js/discussions/16995#discussioncomment-132339
# Install dependencies only when needed
FROM node:lts-alpine AS deps
WORKDIR /opt/app
COPY package.json package-lock.json ./
RUN npm ci
# Rebuild the source code only when needed
FROM node:lts-alpine AS builder
# Add Google Analytics to client code
ARG NEXT_PUBLIC_GOOGLE_ANALYTICS_ID
ENV NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=$NEXT_PUBLIC_GOOGLE_ANALYTICS_ID
ENV NODE_ENV=production
WORKDIR /opt/app
COPY . .
COPY /opt/app/node_modules ./node_modules
RUN npm run build
# Production image, copy all the files and run next
FROM node:lts-alpine AS runner
WORKDIR /opt/app
ENV NODE_ENV=production
COPY /opt/app/next.config.js ./
COPY /opt/app/public ./public
COPY /opt/app/.next ./.next
COPY /opt/app/node_modules ./node_modules
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
# ENV NEXT_TELEMETRY_DISABLED 1
CMD ["node_modules/.bin/next", "start"]
Github action
Here we are using Github package registry to distribute the package and the login to Digital Ocean and deploy it. All the secrets in this file are described below.
.github/workflows/build-and-deploy.yml
name: Build and Deploy
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [main]
workflow_dispatch:
inputs:
logLevel:
description: "Log level"
required: true
default: "warning"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
container: node:14
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Build and Publish to Github Packages Registry
uses: elgohr/Publish-Docker-Github-Action@master
env:
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: ${{ secrets.APP_NEXT_PUBLIC_GOOGLE_ANALYTICS_ID }}
with:
name: jarnesjo/jarnesjo.com/nextjs
registry: docker.pkg.github.com
username: ${{ secrets.USERNAME }}
password: ${{ secrets.GITHUB_TOKEN }}
dockerfile: Dockerfile
buildargs: NEXT_PUBLIC_GOOGLE_ANALYTICS_ID
tags: latest
- name: Deploy package to digitalocean
uses: appleboy/ssh-action@master
env:
GITHUB_USERNAME: ${{ secrets.USERNAME }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
port: ${{ secrets.DEPLOY_PORT }}
envs: GITHUB_USERNAME, GITHUB_TOKEN
script: |
docker login docker.pkg.github.com -u $GITHUB_USERNAME -p $GITHUB_TOKEN
docker pull docker.pkg.github.com/jarnesjo/jarnesjo.com/nextjs:latest
docker stop jarnesjo.com
docker system prune -f
docker run --name jarnesjo.com -dit -p 3000:3000 docker.pkg.github.com/jarnesjo/jarnesjo.com/nextjs:latest
Github secrets
APP_NEXT_PUBLIC_GOOGLE_ANALYTICS_ID - Google Analytics code injected to client code
DEPLOY_HOST - IP to Digital Ocean (DO) droplet
DEPLOY_KEY - SSH secret and the public key should be added to `.ssh/authorized_keys` on server
DEPLOY_PORT - SSH port (22)
DEPLOY_USER - User on droplet (for Forge: `forge`)
USERNAME - Your Github username
Hope it can give you inspiration to your setup up and if you don't want to go with standard Vercel setup.
Discuss this post on Twitter
Categorycode