This guide details how to secure a personal website with HTTPS using NGINX, Let’s Encrypt, and Certbot. It includes both public and homelab use cases, with DNS-based TLS validation for internal domains.
- Public-facing website (e.g.,
info.gg3.dev) - Internal domains with Cloudflare DNS (e.g.,
jenkins.gg3.dev) - HTTPS for secure access to self-hosted services
- Auto-renewing TLS certificates
- Registered domain name (e.g.
gg3.dev) - NGINX installed
- Certbot and DNS plugin installed
- Root access and public IP (for WAN setups)
- DNS access via registrar or Cloudflare
sudo apt install nginx certbot python3-certbot-nginx- NGINX server block configured for domain
- Certbot with http-01 or dns-01 challenge
- HTTPS served on port 443
[Browser] → [NGINX (80/443)] → [Static Content or Proxy Service]
sudo mkdir -p /var/www/info
sudo nano /var/www/info/index.htmlsudo nano /etc/nginx/sites-available/info.gg3.devPaste:
server {
listen 80 default_server;
server_name info.gg3.dev;
root /var/www/info;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location /.well-known/acme-challenge/ {
root /var/lib/letsencrypt/;
default_type "text/plain";
allow all;
}
}Enable the config:
sudo ln -s /etc/nginx/sites-available/info.gg3.dev /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxEnsure ports are open:
sudo ufw allow 80
sudo ufw allow 443Test NGINX access:
curl -H "Host: info.gg3.dev" http://localhostOptional: forward ports 80/443 on router for external access.
- Create an A record pointing
info→ your public IP
- Add
/etc/hostsentries or use pfSense DNS:
10.10.10.10 info.gg3.devIf using Cloudflare, disable proxy (gray cloud) temporarily for http-01.
| Problem | Fix |
|---|---|
| 403 or 404 error | Ensure correct .well-known location |
| Timeout or connection err | Confirm port 80 is forwarded and not firewalled |
| Wrong default server | Make sure correct default_server block is loaded |
| Cert not renewing | Try sudo certbot renew --dry-run |
location /.well-known/acme-challenge/is required for Certbot to verify domain ownership- Using separate server block avoids rewriting main site logic
- Redirecting HTTP → HTTPS ensures security across all entry points
Test validation manually:
echo "hello world" | sudo tee /var/lib/letsencrypt/.well-known/acme-challenge/testThen open: http://info.gg3.dev/.well-known/acme-challenge/test
sudo certbot --nginx -d info.gg3.devCertbot will:
- Perform the challenge
- Modify NGINX config to use SSL
- Reload NGINX with HTTPS enabled
Choose to redirect HTTP → HTTPS when prompted.
Manual redirect:
server {
listen 80;
server_name info.gg3.dev;
return 301 https://$host$request_uri;
}“Setting this up helped me understand how validation works under the hood, and made me appreciate the elegance of DNS-01 in internal networks.”
Project by Juan Garcia (@0xjuang)
Signed: 0x1G
Part of the Oak Root Collective
Scaling Quietly, Branching Endlessly
gg3.dev
Curated under the GG3 Infrastructure Stack – designed for reproducibility, auditability, and clarity.