Nextjs Deploy Docker Nginx Gitlab
Here is a small summary to deploy using Gitlab runner your NextJs application server by NGINX server.
- Gitlab Runner: Deploy of our NextJs site hosted in Gitlab Repo(OnPremise/Gitlab.com)
- NGINX: Server NextJs site static generated files
Dockerfile - It uses the node 14 image for building, then it copies the static files in the nginx image.
The Dockerfile could be simplified by performing the NextJs build directly on the Gitlab runner and then COPY
the builded artifact within the nginx container.
# pull official base image
FROM node:14.19.0-alpine as build
# copy the package.json to install dependencies
COPY package.json package-lock.json ./
# Install the dependencies and make the folder
RUN npm install && mkdir /nextjs-ui && mv ./node_modules ./nextjs-ui
WORKDIR /nextjs-ui
COPY . .
# Build the project and copy the files
RUN npm run build
# NGINX Image Build
FROM nginx:1.17-alpine
## Remove default nginx index page
RUN rm -rf /usr/share/nginx/html/*
COPY --from=build /nextjs-ui/out /usr/share/nginx/html
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
VOLUME /usr/share/nginx/html
VOLUME /etc/nginx
# Don't run as root
USER 101
EXPOSE 8080
gitlab-ci.yml - Here we go through the docker image building process and docker stack deployment on our docker swarm cluster.
In my case am deploying on Docker Swarm, so I use the before_script
section to configure the ssh configuration to deploy on the docker swarm manager node. Later the steps are very simple, we build our docker image and we push it to our Gitlab registry, then we deploy the docker stack or service.
before_script:
- 'which ssh-agent || ( apk update && apk add openssh-client )'
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- touch ~/.ssh/known_hosts
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
stages:
- build
- deploy
build:
cache: {}
stage: build
image: docker:git
variables:
DOCKER_DRIVER: overlay
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN ${CI_REGISTRY}
- docker build --no-cache -t ${CI_REGISTRY}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:staging .
- docker push ${CI_REGISTRY}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:staging
environment:
name: development
rules:
- if: $CI_COMMIT_BRANCH == "master"
deploy:
stage: deploy
variables:
DOCKER_HOST: ssh://docker@docker-host
SERVICE_NAME: my-nextjs-app
image: docker:latest
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
- docker stack deploy --with-registry-auth --compose-file=docker-compose.yml ${SERVICE_NAME}
environment:
name: development
url: https://domain.example
rules:
- if: $CI_COMMIT_BRANCH == "master"
docker-compose.yml - This is a very simple compose file which take our previously builded image and deploy using Traefik labels.
version: '3'
services:
web:
image: "${CI_REGISTRY}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:staging"
ports:
- "8080"
networks:
- traefik-net
deploy:
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik-net"
- "traefik.http.routers.nextjs-router.rule=Host(`domain.example`)"
- "traefik.http.routers.nextjs-router.entrypoints=https"
- "traefik.http.services.nextjs-router.loadbalancer.server.port=8080"
- "traefik.http.routers.nextjs-router.tls.certresolver=certbot"
networks:
traefik-net:
external: true
default.conf - this is our NGINX configuration, as you could see in our Dockerfile we COPY
nginx configurations from the nginx/
folder in our repo to /etc/nginx/conf.d
. This will tell nginx how to serve NextJs static files.
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html;
location ~ /.+ {
try_files $uri $uri.html $uri =404;
}
location / {
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
With this configuration we can successfully deploy our NextJs site using Gitlab Runner, Docker and NGINX.