Dockerize Node App

Great way to show off your app, with the idea that it always works on every OS. Well that the idea.

This article expect you to have Docker Hub account, and understand about NodeJS.

First you need to know what Node version your project running, you can’t pick the latest one without testing for errors. That why I save my node versions in my project, for example: node -v > .nvmrc.

My current node version on my project is: v14.4.
And I’ll lookup Alpine with version 14.4: 14.4-alpine.

I only care Major and Minor versions.
Luckily Node cares to dockerize their versions, it’s a good time to be alive, right? Before I had to install a could-be-working version for Alpine.

Dockerfile

FROM node:14.4-alpine

EXPOSE 3000

ENV NODE_ENV=production
ENV PORT=3000
ENV NODE_WORKDIR=/app
WORKDIR $NODE_WORKDIR

COPY package.json $NODE_WORKDIR/
RUN npm shrinkwrap
RUN npm i
COPY . $NODE_WORKDIR

CMD ["npm", "run", "docker"]
File: Dockerfile

Optional: .dockerignore

# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
# .nuxt

# Nuxt generate
dist

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless

# IDE / Editor
.idea

# Service worker
sw.*

# Mac OSX
.DS_Store

# Vim swap files
*.swp

# VSCode Settings
.vscode

# APP IGNORES
db/
data/
package-lock.json
.git
.docker-mount
File: .dockerignore
Took this from Nuxt .gitignore and convert to .dockerignore and made few changes, special for Docker

Add package.json run commands

{
	"scripts": {
		"docker": "cross-env NODE_ENV=production node server/index",
		"docker-build": "nuxt build && docker build -t dockeruser/node-app .",
 		"docker-run": "docker run --rm -p 8888:3000 dockeruser/node-app",
		"docker-push": "npm run docker-build && docker push dockeruser/node-app"
	}
}
Snippet: package.json
- docker: The production mode running a node app.
- docker-build: Build your app, then run Docker build command, when you save your docker app name to forget.
- docker-run: Run docker container on your local machine port 8888.
- docker-push: Build app and dockerize, then push to your Docker Hub.

Example running command

# Run docker container on your local machine port 8888
npm run docker-run

Run your node as 0.0.0.0

Make sure your node app runs host: 0.0.0.0 instead of host: localhost.

nuxt.config.js

module.exports = {
  server: {
    host: '0.0.0.0'
  }
}
Snippet: nuxt.config.js

(Optional) docker-compose.yml

version: '2'

services:
  node-app:
    build:
      context: .
    image: dockeruser/node-app
    # ports:
    #   - '3000:3000'
    restart: always

# create network: docker network create shared-network
networks:
  default:
    external:
      name: shared-network

(Optional) Nginx (SSL)

# node-app.sylo.space
server {
	# listen 80;
	# listen [::]:80;
	server_name ~^node-app(\.sylo\.space)?$;
	return 301 https://$host$request_uri;
}

server {
    include /nginx/snippets/ssl-sylo-space.conf;
    server_name ~^node-app(\.sylo\.space)?$;
    resolver 127.0.0.11 valid=30s;
    set $upstream http://node-app:3000;
    include /nginx/snippets/snippet-server-location-upstream.conf;
    client_max_body_size 100m;
}
File: nginx/enabled/node-app.sylo.space.conf
snipper-server-location-upstream.conf

Conclusion

You can show your potential employer your node app, by telling them:

“Hey, install Docker Desktop and run:”

# pull image from Docker Hub
docker pull dockeruser/node-app
# run docker container
docker run --rm -p 3000:3000 -it dockeruser/node-app

“And head to the browser: localhost:3000”.