Full Blog TOC

Full Blog Table Of Content with Keywords Available HERE

Wednesday, January 1, 2025

Setting Up a Publicly Accessible VM with Docker, Nginx, and SSL on GCP


In this post we review the step to setup a publicly accessible web site.

The web site is based on a docker container running the famous juice-shop in a GCP based VM. 

We use Let's Encrypt to produce a valid SSL certificate for the site.


All the steps below are using "demo" prefix for the entities. Make sure to use your own suitable prefix instead.


GCP Steps

Add VPC

Login to the GCP console and open the GCP VPC network service.

Create a new VPC network named demo-vpc.
  • use IPv4
  • add a subnet 
  • add Firewall rules to allow TCP ports 22 (SSH), 80 (HTTP), 443(HTTPS)

Add VM

Open the GCP compute engine service.
Add new VM named demo-vm.
Stop the VM, and wait for the stopping to complete.
Edit the VM, and update the VM network interfaces to use the demo-vpc.
Start the VM.


Open the GCP VPC network service, and select IP addresses.
Reserve new external static IP named demo-static-ip, and assign it to the VM.

Add DNS

Open the GCP cloud domains service.
Add new domain registration named demo.com, and complete the verification process.


Open the GCP networking service, and select cloud DNS.
Click on the demo-com zone.
Add a standard A-record www.demo.com, and set the IP to the value of demo-static-ip.

Site Steps

Create Docker Compose

Open the GCP compute engine service.
Click on the demo-vm, and connect using SSH button.
Install docker on the machine, and enable non-root access.
Create docker-compose.yaml file:


version: '3'

services:
juiceshop:
image: bkimminich/juice-shop
container_name: juiceshop
environment:
- NODE_ENV=production
ports:
- "3000:3000"
restart: always

nginx:
image: nginx:latest
container_name: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
ports:
- "80:80"
- "443:443"
depends_on:
- juiceshop
restart: always

certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
restart: always


Create NGINX


Create nginx.conf file:



events {
use epoll;
worker_connections 128;
}

error_log /var/log/nginx.log info;

http {


server {
listen 80;
server_name www.demo.com;

location / {
proxy_pass http://juiceshop:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}

server {
listen 443;
server_name www.demo.com;
#replace with this block later
#listen 443 ssl;
#server_name www.demo.com;
#ssl_certificate /etc/letsencrypt/live/www.demo.com/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/www.demo.com/privkey.pem;

location / {
proxy_pass http://juiceshop:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}


Notice that the nginx.conf SSL section is commented out. We will revive it after issuing a valid certificate.

Create SSL Certification 


Start the containers:
docker compose up -d

Initiate a certificate request:
docker-compose exec certbot certbot certonly --webroot --webroot-path=/var/www/certbot -d www.demo.com --email your-email@demo.com --agree-tos --non-interactive


Update the nginx.conf, and revive the commented SSL section.
Restart the containers:
docker compose restart


Final Note

I have created this post since that is a common practice required for many engineer, but the information is scattered over the sites with many mistakes. 

When following these steps, make sure to validate that each step has successfully completed. For example - check connection to the public IP from a client machine, check DNS resolution, etc.


No comments:

Post a Comment