NGiNX: Using Vercel as Fallback for Reverse Proxy
Over the last ten years I've started being more conscious of my energy usage, and have been trying to reduce my carbon footprint. About a year ago, I found OhmConnect, a program that pays you to save energy during peak hours by turning off your non-critical electronics automatically by connecting your smart plugs or devices like your thermostat.
I have smart plugs that I use to turn off my auxiliary/non-critical electronics during peak hours, including my home lab, so is important that I had a backup for my site when my server is off.
I use Vercel as a backup for my site, and have set up NGiNX on an EC2 instance as a reverse proxy to serve from my homelab, and to fall back to Vercel if my server is down.
NGiNX Reverse Proxy
NGiNX is a great web server, and is very easy to set up as a reverse proxy. I won't go into detail on how to set up NGiNX, but you can find a great guide here.
Once you have NGiNX installed, you can set up a reverse proxy by adding a new server block to your sites-available
directory. For example, I started with a server block for my personal site, which looks like this:
server {
listen 443 ssl;
server_name *.l422y.com l422y.com;
ssl_certificate /etc/letsencrypt/live/l422y.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/l422y.com/privkey.pem;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
location / {
proxy_pass http://10.1.1.2:30004;
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;
}
}
This is a pretty standard server block, and it works great. However, if the server at 10.1.1.2
is down, NGiNX will
return a 502 or 504 error. This is where Vercel comes in.
Vercel as Fallback
Vercel is a great service for hosting static sites, and it's free tier is very generous. I use Vercel to host a static version of my site, which is served when the primary server is down. I do have to make some allowances as Vercel doesn't support some of the server side features I use, but it works great for a temporary fallback.
To set up Vercel as a fallback, first I added an upstream server to my NGiNX config:
upstream backend {
server 10.1.1.2:3004 max_fails=3 fail_timeout=30s;
}
This tells NGiNX to try to connect to the server at 10.1.1.2
on port 3004
, and to try up to 3 times before giving up
for 30 seconds. This is important, as it prevents NGiNX from constantly trying to connect to a server that is down.
After the 30 second timeout, NGiNX will try again, and if the server is still down, it will return a 502 error.
Next, I added a the @fallback location/alias block to my server block:
# Fallback location block
location @fallback {
proxy_pass https://mysite-main.vercel.app; # Replace with your Vercel URL
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;
}
This is where we will send requests if the primary server is down. I also added a proxy_set_header
directive to make
sure the correct host is passed to Vercel.
Finally, I updated the location block for my site to use the upstream server, and to use the fallback location if the upstream server is down:
location / {
proxy_pass http://backend;
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;
proxy_connect_timeout 50ms; # Adjust this to match your needs, I have fiber internet so I can set this low
proxy_send_timeout 500ms;
proxy_read_timeout 500ms;
# Define the error page for a bad gateway
error_page 502 504 = @fallback;
}
So, with everything put together, the server block now looks like this:
upstream backend {
server 10.1.1.2:3004 max_fails=3 fail_timeout=30s;
}
server {
listen 443 ssl;
server_name *.l422y.com l422y.com;
ssl_certificate /etc/letsencrypt/live/l422y.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/l422y.com/privkey.pem;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/html;
}
location = /.well-known/acme-challenge/ {
return 404;
}
location / {
proxy_pass http://backend;
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;
proxy_connect_timeout 50ms;
proxy_send_timeout 500ms;
proxy_read_timeout 500ms;
# Define the error page for a bad gateway
error_page 502 504 = @fallback;
}
# Fallback location block
location @fallback {
proxy_pass https://mysite-main.vercel.app; # Replace with your Vercel URL
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;
}
}
And that's it! Now, if the primary server is down, NGiNX will return the version of the site hosted on Vercel.