If you have been building things for a while, you probably have several GitHub Pages sites spread across different repositories. A personal landing page at username.github.io/portfolio, a resume at username.github.io/resume, maybe a blog at username.github.io/blog. Each one is a separate site with its own repository and its own URL.
This works fine until you want to present yourself professionally. Sending someone to username.github.io/resume is functional, but it does not look as clean as yourdomain.com/resume. The instinct is to buy multiple domains or subdomains and point each one at the corresponding repository. That gets expensive and hard to manage quickly.
There is a better way. With a single VPS and NGINX, you can unify all of your GitHub Pages sites under one domain without touching your repositories at all. This article walks through the full setup: configuring NGINX as a reverse proxy, routing multiple paths to separate GitHub Pages sites, and hardening the server.
NGINX will sit in front of all your GitHub Pages sites and act as a reverse proxy. When a request comes in for yourdomain.com/resume, NGINX intercepts it, fetches the content from username.github.io/resume, and returns it to the visitor. From the outside, everything looks like it lives at your domain. GitHub Pages still does the actual hosting.
The key directive that makes this possible is proxy_pass. It tells NGINX where to forward incoming requests. Combined with proxy_set_header, you can pass the correct Host header to GitHub so it knows which page to serve.
yourdomain.com)Connect to your VPS via SSH, switch to root, and install NGINX:
Create a new configuration file in /etc/nginx/sites-available/ named after your domain:
Then enable it by creating a symlink in sites-enabled:
Paste the following configuration in the configuration file, replacing yourdomain.com and username with your own values:
80 / listen [::]:80 — listen for incoming HTTP connections on IPv4 and IPv6.server_name — the domain this server block responds to. NGINX uses this to route requests when multiple server blocks are defined.proxy_set_header Host — this is critical. GitHub Pages uses the Host header to determine which site to serve. Without setting it to your GitHub Pages hostname, GitHub will return a 404.proxy_set_header X-Real-IP — forwards the original visitor's IP to your logs instead of the proxy's own address.proxy_pass — the upstream URL where NGINX forwards the request for each location block. Note the trailing slash: it is required for path rewriting to work correctly.NGINX matches location blocks from most specific to least specific. The / block is a catch-all and should always go last. More specific paths like /resume and /blog take priority and get matched first.
Before reloading NGINX, verify the configuration has no syntax errors:
If the output says syntax is ok and test is successful, apply the new configuration:
NGINX does not need a full restart — reload applies changes gracefully without dropping active connections.
Create an A record in your DNS provider pointing your domain to your VPS's public IP. DNS propagation may take a few minutes to a few hours.
Once you have your VPS running, you should lock down SSH access:
PasswordAuthentication no in /etc/ssh/sshd_configPermitRootLogin nofail2ban to block repeated failed login attemptsSee: How to Set Up SSH Keys on Debian 11
Routing your domain through Cloudflare adds DDoS protection, hides your VPS's real IP address, and gives you free analytics. Point your domain's nameservers to Cloudflare, then configure the DNS records there with the proxy enabled (the orange cloud icon).
With Cloudflare in front, your VPS only needs to accept connections from Cloudflare's IP ranges. You can configure iptables or ufw to drop all traffic on ports 80 and 443 that does not originate from a Cloudflare IP. Cloudflare publishes its current IP ranges at cloudflare.com/ips.
To see real visitor IPs in your NGINX logs instead of Cloudflare's IPs, you need to restore the original IP using the ngx_http_realip_module.
See: ergin/nginx-cloudflare-real-ip
You now have a single NGINX instance serving as a unified front door for all your GitHub Pages sites. Adding a new site is as simple as adding a new location block to your configuration, running nginx -t, and then nginx -s reload. No new domains to buy, no new DNS zones to manage.
The cost is one small VPS, which you probably have some use for anyway. The benefit is a clean, professional URL structure for everything you build.