DEV Community

Cover image for How to Deploy a Spring Boot and Angular App on DigitalOcean with Docker, Nginx, and HTTPS
Shahid Foy
Shahid Foy

Posted on

How to Deploy a Spring Boot and Angular App on DigitalOcean with Docker, Nginx, and HTTPS

I have been working a side project called N1netails which is an open-source project that provides practical alerts and monitoring for applications. I wanted to share what I learned on how to deploy my application to DigitalOcean. One thing to note is the project is primarily written in Springboot. Even the UI is an Angular application wrapped inside of Springboot. So if you are deploying an Angular application by itself you will have to modify some of steps for docker compose and nginx. You can view the result of my deployment here N1netails Dashboard.

🌐 N1neTails DigitalOcean Deployment Guide

This guide walks you through setting up the N1neTails application with Docker Compose and configuring Nginx as a reverse proxy on a Digitalocean Ubuntu server.

  • Table of Contents
    • Postgres Database
    • Domain or subdomain
    • Docker setup
    • Nginx setup
    • Setup HTTPS with certbot

1. Create Postgres Database

For this implementation I decided to use DigitalOcean to host my Database Cluster.
You can read more about setting up Database Clusters on DigitalOcean here:
https://docs.digitalocean.com/products/databases/postgresql/how-to/create/

DigitalOcean makes it easy to create new users and databases within your cluster.
Steps 1 & 2 can be done on DigitalOcean but are provided in case your database is hosted elsewhere.

Step 1: Create n1netails user (can be done on DigitalOcean):

CREATE USER n1netails WITH PASSWORD 'your_password'; 
Enter fullscreen mode Exit fullscreen mode

Step 2: Create n1netails database (can be done on DigitalOcean):

CREATE DATABASE "n1netails" WITH OWNER = n1netails ENCODING = 'UTF8' LOCALE_PROVIDER = 'libc' CONNECTION LIMIT = -1 IS_TEMPLATE = False; 
Enter fullscreen mode Exit fullscreen mode

Step 3: Grant n1netails user access to n1netails database:

GRANT CREATE ON DATABASE n1netails TO n1netails; 
Enter fullscreen mode Exit fullscreen mode

Step 4: Generate ntail schema:

CREATE SCHEMA IF NOT EXISTS ntail AUTHORIZATION n1netails; 
Enter fullscreen mode Exit fullscreen mode

Step 5: Set timezone to UTC:

ALTER DATABASE n1netails SET timezone TO 'Etc/UTC'; 
Enter fullscreen mode Exit fullscreen mode

2. Create a Subdomain (e.g., app.n1netails.com)

You can set up n1netails using your own domain or subdomain.
You can configure DNS settings where you registered your domain (e.g., Squarespace, GoDaddy, Namecheap).

Add an A Record:

  • Host: app
  • Type: A
  • Value: Your server’s public IP address
  • TTL: Default (3600)

Save the DNS settings.

πŸ“Œ It may take a few minutes (or up to 24 hours) for DNS to propagate.

3. Docker Compose Setup

Set up docker compose on ubuntu by following these docs:

Add the following directories within the digital ocean server projects/n1netails

Create a docker-compose.yml file inside of projects/n1netails with the following content:

services: api: image: shahidfo/n1netails-api:latest container_name: n1netails-api ports: - "9901:9901" depends_on: liquibase: condition: service_completed_successfully environment: SPRING_PROFILE_ACTIVE: docker SPRING_DATASOURCE_URL: jdbc:postgresql://<digital-ocean-postgres-db-url>:<digital-ocean-postgres-db-port>/n1netails SPRING_DATASOURCE_USERNAME: n1netails SPRING_DATASOURCE_PASSWORD: <n1netails_password> N1NETAILS_PASSKEY_RELYING_PARTY_ID: <domain-url> # e.g. app.n1netails.com N1NETAILS_PASSKEY_ORIGINS: https://<domain-url> # e.g. https://app.n1netails.com OPENAI_ENABLED: true OPENAI_API_KEY: <your_openai_api_key> OPENAI_API_URL: https://api.openai.com ui: image: shahidfo/n1netails-ui:latest container_name: n1netails-ui ports: - "9900:9900" depends_on: - api environment: SPRING_PROFILE_ACTIVE: docker API_BASE_URL: https://<domain-url> OPENAI_ENABLED: true liquibase: image: shahidfo/n1netails-liquibase:latest container_name: n1netails-liquibase environment: SPRING_PROFILE_ACTIVE: docker SPRING_DATASOURCE_URL: jdbc:postgresql://<digital-ocean-postgres-db-url>:<digital-ocean-postgres-db-port>/n1netails SPRING_DATASOURCE_USERNAME: n1netails SPRING_DATASOURCE_PASSWORD: <n1netails_password> 
Enter fullscreen mode Exit fullscreen mode

Prepare Docker Compose with above config and deploy:

# Stop and remove old containers docker compose down -v # Start containers in detached mode docker compose up -d # tail docker logs (optional) docker compose logs -f 
Enter fullscreen mode Exit fullscreen mode

4. Nginx Setup

Step 1: Install Nginx on your server if not installed:

# Update the package list to ensure you get the latest available versions sudo apt update # Install the Nginx web server sudo apt install nginx 
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the Nginx config file

Create the file /etc/nginx/sites-available/n1netails.conf with the following content:

server { listen 80; server_name <domain-url>; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; add_header X-XSS-Protection "1; mode=block"; # Route API calls to backend location /ninetails/ { proxy_pass http://localhost:9901/ninetails/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # Route OpenAPI config (Swagger needs this) location /v3/ { proxy_pass http://localhost:9901/v3/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # Route Swagger UI to backend location /swagger-ui/ { proxy_pass http://localhost:9901/swagger-ui/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # Route all other requests to frontend location / { proxy_pass http://localhost:9900/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } 
Enter fullscreen mode Exit fullscreen mode

Step 3: Enable the site and disable default

# Enable the new site sudo ln -s /etc/nginx/sites-available/n1netails.conf /etc/nginx/sites-enabled/n1netails.conf # Disable the default site sudo rm /etc/nginx/sites-enabled/default 
Enter fullscreen mode Exit fullscreen mode

Step 4: Test and reload Nginx

# Test the Nginx configuration for syntax errors sudo nginx -t # Reload Nginx to apply the new configuration without downtime sudo systemctl reload nginx # Check nginx logs sudo tail -f /var/log/nginx/error.log 
Enter fullscreen mode Exit fullscreen mode

5. Install Certbot & Enable HTTPS

# Update packages sudo apt update # Install Certbot and Nginx plugin sudo apt install certbot python3-certbot-nginx 
Enter fullscreen mode Exit fullscreen mode

Then run:

# Automatically obtain and configure SSL sudo certbot --nginx 
Enter fullscreen mode Exit fullscreen mode

Follow the prompts:

  • Choose your subdomain (e.g., app.n1netails.com)
  • Redirect HTTP to HTTPS when prompted βœ…

βœ… You now have HTTPS enabled.


Step 1: Verify HTTPS

Visit:

Visit your domain to varify https

Example

https://app.n1netails.com 
Enter fullscreen mode Exit fullscreen mode

Check for the padlock icon in the address bar.


Step 2: Enable SSL Certificate Auto-Renewal

Let’s Encrypt certificates expire every 90 days. Certbot sets up a systemd timer automatically.

Verify with:

systemctl list-timers | grep certbot 
Enter fullscreen mode Exit fullscreen mode

Test the renewal process:

sudo certbot renew --dry-run 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)