Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save prateekrajgautam/21d4b8a34821e58e0f1c0fda1ba149af to your computer and use it in GitHub Desktop.

Select an option

Save prateekrajgautam/21d4b8a34821e58e0f1c0fda1ba149af to your computer and use it in GitHub Desktop.
GitHub Pages + Cloudflare Tunnel + Nginx Proxy Manager + SSH over Cloudflare Tunnel (NixOS)

GitHub Pages + Cloudflare Tunnel + Nginx Proxy Manager + SSH over Cloudflare Tunnel (NixOS)

Final architecture:

example.com                  -> GitHub Pages
www.example.com              -> GitHub Pages
docs.example.com             -> GitHub Pages

*.example.com                -> Cloudflare Tunnel
Cloudflare Tunnel            -> Nginx Proxy Manager
NPM                          -> Internal Services

ssh.example.com              -> SSH over Cloudflare Access

Examples:

api.example.com              -> FastAPI
db.example.com               -> pgAdmin
git.example.com              -> Gitea
grafana.example.com          -> Grafana
ssh.example.com              -> SSH server

1. Requirements

You need:

  • Domain in Cloudflare
  • GitHub account
  • NixOS server
  • Docker installed
  • Ports NOT forwarded on router

Recommended:

NO public ports
NO DDNS
NO reverse port forwarding

Cloudflare Tunnel handles everything outbound.


2. Configure GitHub Pages


Create repository

Example:

username.github.io

OR any repo.

Enable Pages:

GitHub
→ Repository
→ Settings
→ Pages

Add CNAME file

Create:

CNAME

Contents:

example.com

3. Configure Cloudflare DNS

Open:

Cloudflare Dashboard
→ DNS

Add GitHub Pages Records

A       @       185.199.108.153
A       @       185.199.109.153
A       @       185.199.110.153
A       @       185.199.111.153

CNAME   www     username.github.io
CNAME   docs    username.github.io

These subdomains go directly to GitHub Pages.


Add Wildcard Tunnel Record

CNAME   *       YOUR_TUNNEL_ID.cfargotunnel.com

Important:

Specific DNS records override wildcard.

Result:

Domain Destination
docs.example.com GitHub
api.example.com Tunnel
db.example.com Tunnel
anything.example.com Tunnel

4. Install cloudflared on NixOS

Edit:

/etc/nixos/configuration.nix

Add:

environment.systemPackages = with pkgs; [
  cloudflared
];

Rebuild:

sudo nixos-rebuild switch

5. Authenticate cloudflared

Run:

cloudflared tunnel login

Browser opens.

Select domain.

Creates:

~/.cloudflared/cert.pem

6. Create Tunnel

cloudflared tunnel create homelab

Example output:

Tunnel credentials written to:

/root/.cloudflared/UUID.json

Save:

  • Tunnel UUID
  • JSON path

7. Create Tunnel Config

Create directory:

sudo mkdir -p /etc/cloudflared

Create:

sudo nano /etc/cloudflared/config.yml

8. Configure Tunnel Ingress

Replace UUID.

tunnel: YOUR_TUNNEL_UUID

credentials-file: /root/.cloudflared/YOUR_TUNNEL_UUID.json

ingress:

  # SSH
  - hostname: ssh.example.com
    service: ssh://localhost:22

  # Everything else
  - hostname: "*.example.com"
    service: http://localhost:80

  - service: http_status:404

Explanation:

ssh.example.com
    -> SSH daemon

everything else
    -> NPM

9. Create cloudflared Service on NixOS

Edit:

/etc/nixos/configuration.nix

Add:

systemd.services.cloudflared = {
  description = "Cloudflare Tunnel";
  after = [ "network-online.target" ];
  wantedBy = [ "multi-user.target" ];

  serviceConfig = {
    ExecStart = "${pkgs.cloudflared}/bin/cloudflared --config /etc/cloudflared/config.yml tunnel run";
    Restart = "always";
    RestartSec = "5s";
  };
};

Rebuild:

sudo nixos-rebuild switch

Start:

sudo systemctl start cloudflared

Enable:

sudo systemctl enable cloudflared

Check:

systemctl status cloudflared

10. Install Docker on NixOS

Add:

virtualisation.docker.enable = true;

users.users.YOUR_USER.extraGroups = [ "docker" ];

Rebuild:

sudo nixos-rebuild switch

Logout/login.


11. Install Nginx Proxy Manager

Create directory:

mkdir ~/npm
cd ~/npm

Create:

docker-compose.yml
services:
  npm:
    image: jc21/nginx-proxy-manager:latest

    container_name: npm

    restart: unless-stopped

    ports:
      - "80:80"
      - "81:81"
      - "443:443"

    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

Start:

docker compose up -d

12. Open NPM Dashboard

Open locally:

http://SERVER_IP:81

Default:

admin@example.com
changeme

Change password immediately.

Project:

Nginx Proxy Manager GitHub


13. Add Proxy Hosts in NPM

Example:

FastAPI

api.example.com

Forward to:

192.168.1.10:8000

Grafana

grafana.example.com

192.168.1.20:3000

14. Configure Cloudflare Access for SSH

Open:

Cloudflare Zero Trust Dashboard

Go:

Access
→ Applications
→ Add Application

Choose:

Self-hosted

Configure SSH App

Application domain:

ssh.example.com

Session duration:

24h

Policy:

Allow
→ Your email

Example:

you@gmail.com

Save.


15. Install cloudflared on Client Machine

Linux:

sudo apt install cloudflared

NixOS:

environment.systemPackages = with pkgs; [
  cloudflared
];

16. Configure SSH Client

Edit:

~/.ssh/config

Add:

Host ssh.example.com
    ProxyCommand cloudflared access ssh --hostname %h
    User YOUR_USER

Modern OpenSSH usually does NOT require:

HostKeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa

Only add them if older servers require RSA compatibility.


17. Connect Through Tunnel

Now simply run:

ssh ssh.example.com

Flow:

SSH Client
    ↓
cloudflared access ssh
    ↓
Cloudflare Access Authentication
    ↓
Tunnel
    ↓
SSH Server

No:

  • Public SSH port
  • VPN
  • Port forwarding

18. Optional: Browser Authentication

First connection may open browser for Cloudflare authentication.

After login:

Access token cached locally

Future SSH connections become seamless.


19. Verify Tunnel

Check logs:

journalctl -u cloudflared -f

20. Useful Commands

Restart tunnel

sudo systemctl restart cloudflared

Test tunnel manually

cloudflared tunnel --config /etc/cloudflared/config.yml run

Docker containers

docker ps

21. Recommended Security

Protect these with Cloudflare Access:

  • NPM dashboard
  • Grafana
  • pgAdmin
  • Portainer
  • Gitea

Example:

Allow only:
  *@yourdomain.com

22. Important Notes


Do NOT Port Forward

Avoid:

Router:
80
443
22

Tunnel removes need entirely.


SSH Security Advantage

Your SSH server becomes invisible publicly.

Only Cloudflare edge can reach it.

Huge reduction in attack surface.


23. Final Recommended Structure

GitHub Pages

example.com
www.example.com
docs.example.com

Tunnel + NPM

Automatically handled:

api.example.com
db.example.com
grafana.example.com
git.example.com

SSH

ssh.example.com

through Cloudflare Access.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment