Deploying next.js with Docker, GIT hooks and NGINX

You have a next.js project in a local GIT repository, and you want to deploy it simply by pushing to a remote GIT repository. In this article I’ll show you how I did it.

Today I was creating my new minimalistic homepage nickredmark.com, with next.js. I wanted to deploy it with now, which is superhandy, but I saw that custom domains require a premium account. Since I already have a Virtual Private Server I thought it would make sense to use it. It took me a morning to put everything together, so I decided to share my solution with the interwebs.

Adding Docker support

Install docker on your server and give your user permissions to use docker without sudo.

Add this Dockerfile to your project.

FROM node:boron
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app
RUN npm install
COPY . /usr/src/app
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]

Add these scripts to your package.json (replace <containername> with the container name of your choice, it’s just an identifier).

"dev": "next",
"build": "next build",
"start": "next start",
"docker:build": "docker build -t <containername> .",
"docker:clean": "docker rm -f <containername> || true",
"docker:run": "docker run -p 7878:3000 -d --name <containername> <containername> && npm run docker:logs",
"docker:stop": "docker stop <containername>",
"docker:start": "docker start <containername> && npm run docker:logs",
"docker:logs": "docker logs -f <containername>",
"deploy": "npm run docker:build && npm run docker:clean && npm run docker:run"

If you have docker installed locally, you can try to deploy the project locally.

npm run deploy

To stop the container use the docker:stop command.

npm run docker:stop

Automating deployment with GIT

On your server, create a bare git repository (using the system originally described here).

mkdir myproject
cd myproject
git init --bare

Create the file hooks/post-receive (copy and paste from here).

In the file, set the variable DEPLOY_ROOT to the directory where you want to deploy (I used /var/www/myproject). The line to replace is

export DEPLOY_ROOT="${HOME}/work"

Also replace the line with POST_UPDATE_CMD= like so:

POST_UPDATE_CMD='cd ${DEPLOY_ROOT} && npm run deploy'

Make the file executable.

chmod +x post-receive

Now, locally, add the remote git repository

git remote add urlofyourremoterepository

Deploy

To deploy, push your code to the remote repository.

git push origin master

Your site should now be visible at

yoursite.com:7878

Expose with NGINX

If you want to display your site at port 80, I recommend you use a reverse proxy like NGINX. The site configuration could be something simple like this.

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name yoursite.com;
location / {
proxy_pass http://localhost:7878;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}

After reloading NGINX, your app should be accessible at

yoursite.com

Conclusion

Certainly there are better ways to to this. A drawback of this approach is that during the deployment, for a moment, the service would be offline. It would be better to deploy a new container while keeping the old one, and then switch the ports with NGINX, but for now this solution is good enough for me. I hope this might help you getting started. If you have comments I’m happy to hear them.

P.S. I put together this solution while creating my new online profile, nickredmark.com — check it out! The source code is available on GitHub, where the code might be more up to date than this article, if you read it in a while.