How I Built a Secure Monitoring Dashboard with Grafana on a $5 VPS – Full Indie Dev Guide

Grafana Login Page with Google SSO Button

As an indie developer based in China and exploring the global indie hacking scene, one of my first projects in 2026 was setting up a fully secure Grafana monitoring dashboard on a budget VPS – all for less than $5 per month. No expensive SaaS tools, no privacy compromises, and full professional polish.

This post is a complete, step-by-step guide based on my real deployment. Everything is production-ready: custom domain, free HTTPS, Google one-click login with built-in MFA, and Nginx reverse proxy.

Why I Built This

  • Ultra-low cost: VPS (~$9.9/year) + domain (~$2–10/year, very cheap)
  • Complete control: All data stays on my own server
  • Professional appearance: Clean domain instead of raw IP:3000
  • Strong security: Google SSO + MFA, no exposed default credentials

Tools & Costs

  • VPS: Racknerd low-cost plan (~$9.9/year)
  • Domain: dm996.icu (annual cost ~$2–10, very affordable)
  • Grafana OSS (free, latest v12.x)
  • Nginx (free)
  • Let’s Encrypt certificate (free, auto-renew)
  • Google OAuth2 (free)

Complete Step-by-Step Deployment

Step 1: Install Grafana from Official Repository

1
2
3
4
5
6
7
8
9
sudo apt install -y apt-transport-https software-properties-common wget
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install grafana -y

sudo systemctl start grafana-server
sudo systemctl enable grafana-server

Initial test access: http://VPS_IP:3000 → Default: admin / admin (change password on first login).

Step 2: Domain Setup & Free HTTPS with Let’s Encrypt

  1. Purchase domain and set A record to VPS public IP.

  2. Open ports 80 & 443:

    1
    2
    3
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw reload
  3. Install Nginx and Certbot:

    1
    2
    3
    4
    sudo apt install nginx -y
    sudo snap install core; sudo snap refresh core
    sudo snap install --classic certbot
    sudo ln -s /snap/bin/certbot /usr/bin/certbot
  4. Obtain certificate:

    1
    sudo certbot --nginx -d dm996.icu

    Choose option 2 (redirect HTTP to HTTPS).

Step 3: Configure Nginx Reverse Proxy

Create site config:

1
sudo nano /etc/nginx/sites-available/grafana

Full configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server {
listen 80;
server_name dm996.icu;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name dm996.icu;

ssl_certificate /etc/letsencrypt/live/dm996.icu/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dm996.icu/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

location / {
proxy_pass http://127.0.0.1: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;

# WebSocket support for Grafana Live
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

Enable and restart:

1
2
3
4
sudo ln -s /etc/nginx/sites-available/grafana /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx

Step 4: Configure Grafana for Domain & Security

1
sudo nano /etc/grafana/grafana.ini

Modify [server] section:

1
2
3
4
[server]
domain = dm996.icu
root_url = https://dm996.icu/
http_addr = 127.0.0.1 # Bind to localhost only (recommended)

Restart Grafana:

1
sudo systemctl restart grafana-server

Step 5: Set Up Google OAuth2 SSO with MFA

  1. Google Cloud Console → APIs & Services → Credentials → Create OAuth Client ID

    • Application type: Web application
    • Authorized redirect URI: https://dm996.icu/login/google
  2. Add to Grafana config:

    1
    sudo nano /etc/grafana/grafana.ini

Add section:

1
2
3
4
5
6
7
8
9
10
11
[auth.google]
enabled = true
name = Google
client_id = YOUR_CLIENT_ID.apps.googleusercontent.com
client_secret = YOUR_CLIENT_SECRET
scopes = openid email profile
auth_url = https://accounts.google.com/o/oauth2/v2/auth
token_url = https://oauth2.googleapis.com/token
api_url = https://openidconnect.googleapis.com/v1/userinfo
allow_sign_up = true
use_pkce = true

Restart:

1
sudo systemctl restart grafana-server
1
2
3
4
5
[auth]
disable_login_form = true # Disable default login form

[auth.google]
allow_sign_up = false # Require manual user approval

Final Result & Lessons Learned

  • Total setup time: ~2 hours
  • Running cost: <$10 in the first year (VPS + domain)
  • Uptime: Zero downtime so far
  • Access URL: https://dm996.icu
  • Privacy & Security: Full control with Google-level authentication

This project became the foundation of my indie dev journey and eventually inspired me to launch this blog to document more self-hosted experiments.