NGiNX: Using Vercel as Fallback for Reverse Proxy

/
117

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.


TOY MODE
π