Deployment scenario: NextJs Static site, separate content repo
This scenario describes a static site being built from two separate repositories, one containing a NextJS based source and a second content repository containing media files, text and necessary configuration / glue files.
A common use case is a static site being rebuilt based on content added through a repository interface like github or gitlab. this is a simpler equivalent to a full blown cms. like so the future content editor only needs to be trained to interface with a common and widely used and supported system.
Infrastructure parts
- client repository site
- client repository content
- mirror repository site
- mirror repository content
- ci system
- container registry
- web server
Deployment pipeline
App updates
- commit is pushed to client app repo
- client app repo is pushed to mirror app repo
- ci executes pipeline on mirror app repo
- clones app code from mirror
- clones content from mirror
- builds container image with web server
- copy files into container
- builds site and merges content
- configures webserver
- pushes image to registry
- triggers deploy on infrastructure
- pulls container image
- restarts service
Content updates
- commit is pushed to client content repo
- client content repo is pushed to mirror content repo
- ci executes pipeline on mirror content repo
- clones mirror app repo
- updates version file with commit hash (stage) or tag (prod) from content repo
- commits change and pushes to client app repo, thereby triggering a run of the App Update pipeline above
Configuration files
- ci pipeline .woodpecker.yml on the site repo
- example deploys the built artefact to a caprover-managed server and notifies via a telegram bot
steps:
clone_content_repo:
image: ubuntu
secrets: [ssh_pubkey_with_read_access]
commands:
- apt-get update -y && apt-get install openssh-client git git-lfs -y
- eval $(ssh-agent -s)
- echo "$ssh_pubkey_with_read_access" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan -p9235 git_server > ~/.ssh/known_hosts
- env
- git clone --depth=1 ssh://git@git_server/${CI_REPO}-content content
- cd content
- git lfs pull
- rm -rf .git
- cd ..
- rm -rf .git
when:
- event: push
branch: [master, main]
- event: tag
build_stage_image:
image: woodpeckerci/plugin-docker-buildx
settings:
registry: package_server
repo: git_server/${CI_REPO}
tag: ${CI_COMMIT_SHA}
username: wellhoster
password:
from_secret: gitea_pass
when:
- event: push
branch: [master, main]
status: success
build_prod_image:
image: woodpeckerci/plugin-docker-buildx
settings:
registry: package_server
repo: git_server/${CI_REPO}
tag: ${CI_COMMIT_TAG}
username: wellhoster
password:
from_secret: gitea_pass
when:
- event: tag
branch: [master, main]
status: success
deploy_prod_site:
image: caprover/cli-caprover:v2.1.1
environment:
- CAPROVER_URL=https://caprover_domain
- CAPROVER_APP=appname
- "CONTAINER_FULL_IMAGE_NAME_WITH_TAG=package_server/${CI_REPO}:${CI_COMMIT_TAG}"
secrets: [ caprover_pass ]
commands:
- caprover deploy --caproverUrl $CAPROVER_URL --caproverPassword $CAPROVER_PASS --caproverApp $CAPROVER_APP --imageName $CONTAINER_FULL_IMAGE_NAME_WITH_TAG
when:
- event: tag
status: success
deploy_stage_site:
image: caprover/cli-caprover:v2.1.1
environment:
- CAPROVER_URL=https://caprover_domain
- CAPROVER_APP=appname
- "CONTAINER_FULL_IMAGE_NAME_WITH_TAG=package_server/${CI_REPO}:${CI_COMMIT_SHA}"
secrets: [ caprover_pass ]
commands:
- caprover deploy --caproverUrl $CAPROVER_URL --caproverPassword $CAPROVER_PASS --caproverApp $CAPROVER_APP --imageName $CONTAINER_FULL_IMAGE_NAME_WITH_TAG
when:
- event: push
branch: [master, main]
status: success
notify:
image: appleboy/drone-telegram
settings:
token:
from_secret: telegram_token
to: 393273328
message: >
✅ Building `${CI_REPO_NAME}` triggered by `${CI_PIPELINE_EVENT}`
This went to prod.
📝 Commit by ${CI_COMMIT_AUTHOR} on `${CI_COMMIT_BRANCH}`:
`${CI_COMMIT_MESSAGE}`
❌ Build ${CI_PIPELINE_EVENT} of `${CI_REPO_NAME}` has status `${CI_PIPELINE_STATUS}`.
This tried to go to prod.
📝 Commit by ${CI_COMMIT_AUTHOR} on `${CI_COMMIT_BRANCH}`:
`${CI_COMMIT_MESSAGE}`
when:
event:
- tag
- push
status:
- success
- failure
Hey! I'll happily receive your comments via email

Andreas Wagner
Freelance System Administrator from Tallinn, Estonia.