Last active
December 25, 2024 02:24
-
-
Save FlyingFathead/cbe69fb1ee1e9b11455f0230ae350cc5 to your computer and use it in GitHub Desktop.
Example reverse proxy/tunnel config for nginx to run i.e. a local Flask web server over a remote VPS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#> Created by FlyingFathead, Oct. 14th, 2024 | |
#> https://github.com/FlyingFathead/ | |
# | |
# Here's an extremely simple example of a reverse tunnel proxy for serving | |
# i.e. a local Flask over a remote VPS running nginx with htpasswd auth. | |
# | |
# .htpasswd with nginx requires 'apache2-utils'. | |
# Install it with: `sudo apt-get install apache2-utils` | |
# (on Debian/Ubuntu tree Linux systems) | |
# | |
# ----------------------------- | |
# Legend (Simplified Topology): | |
# ----------------------------- | |
# | |
# ====================== =================== ======================== | |
# | Your local machine | <==> | Your Remote VPS | <==> | Client, You, Whoever | | |
# ====================== SSH =================== Open ======================== | |
# (runs i.e. Flask, (nginx) Web The user who connects to | |
# its API's, etc.) [ acts as the web the local machine's | |
# server to outside ] services via the web | |
# | |
# NOTE: | |
# ===== | |
# | |
# Please use HTTPS at all times, even if you're setting up a basic testbed. | |
# I.e. Certbot can be used to get your https root certs right. | |
# | |
# This script is NOT for serious production use, but rather just a overall view | |
# on how you _can_ set up simple localhost mini web services (like Flask) so | |
# that they're hosted on a remote VPS over a ssh/autossh reverse tunnel. | |
# | |
# I do recommend i.e. adding another layer of authentication on top of Flask | |
# (i.e. a separate login), token-based authentication (OAuth, JWT), etc. | |
# | |
# ------------------------------------------------------------------------------ | |
# You can create a persisting tunnel to your VPS's backend i.e. with: | |
# ------------------------------------------------------------------------------ | |
# | |
# $ autossh -vvv -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -N -R 127.0.0.1:"$remote_port":localhost:"$local_port" "$remote_username"@"$remote_hostname" | |
# | |
# (note: reverse tunnel keepalives etc may depend on i.e. your ISP's NAT, esp. | |
# if using a mobile data provider) | |
# | |
# ------------- | |
# Placeholders: | |
# ------------- | |
# | |
# - <yourvps.com> = your VPS's address / domain name if you have one. | |
# (same as "$remote_hostname" in the bash script below) | |
# - <yourtunnel_dir> = the tunnel directory name, assuming that you don't want | |
# your services at your server's root. | |
# (i.e. example.com/<yourtunnel_dir>/ <= note: only the name of the directory) | |
# - <remote_port> = remote port on the VPS to forward | |
# | |
# | |
# - The stuff below goes to your: '/etc/nginx/sites-available/default' | |
# - 'sudo nginx -t' to test it. | |
# - 'sudo systemctl reload nginx' to reload nginx after the tests passed. | |
# | |
# Feel free to comment if this example needs something. It's provided AS-IS. | |
# ------------------------------------------------------------------------------ | |
# global; rate limit htpasswd attempts [optional] | |
# limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; | |
server { | |
listen 80; | |
listen [::]:80; | |
server_name <yourvps.com> www.<yourvps.com>; | |
# Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response. | |
return 301 https://$host$request_uri; | |
} | |
## HTTPS Server Block | |
server { | |
listen 443 ssl; | |
listen [::]:443 ssl; | |
server_name <yourvps.com> www.<yourvps.com>; | |
# SSL Configuration | |
ssl_certificate /etc/letsencrypt/live/<yourvps.com>/fullchain.pem; | |
ssl_certificate_key /etc/letsencrypt/live/<yourvps.com>/privkey.pem; | |
include /etc/letsencrypt/options-ssl-nginx.conf; | |
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; | |
root /var/www/html; | |
index index.html index.htm index.nginx-debian.html; | |
access_log /var/log/nginx/access.log main; | |
## Main Site Configuration | |
location / { | |
try_files $uri $uri/ =404; | |
} | |
# Temporary Test Location // Use to test your IP | |
location /test-ip { | |
return 200 "Your IP is $remote_addr\n"; | |
} | |
location /<yourtunnel_dir>/ { | |
## Some rewrite ideas here: | |
# rewrite ^/<yourtunnel_dir>(.*)$ $1 break; | |
# rewrite ^/api/(.*)$ /<yourtunnel_dir>/api/$1 break; | |
# rewrite ^/<yourtunnel_dir>/(.*)$ /$1 break; | |
proxy_pass http://127.0.0.1:<remote_port>/; | |
# This passes the /<yourtunnel_dir> prefix to Flask in the SCRIPT_NAME header, so Flask knows it needs to adjust the reque> | |
proxy_set_header SCRIPT_NAME /<yourtunnel_dir>; | |
# Port where your reverse tunnel is running | |
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; | |
# Handle WebSockets if needed | |
proxy_http_version 1.1; | |
proxy_set_header Upgrade $http_upgrade; | |
proxy_set_header Connection "upgrade"; | |
# Dynamically rewrite URLs in the HTML content | |
sub_filter_once off; | |
sub_filter 'href="/' 'href="/<yourtunnel_dir>/'; | |
sub_filter 'src="/' 'src="/<yourtunnel_dir>/'; | |
sub_filter 'action="/' 'action="/<yourtunnel_dir>/'; | |
sub_filter 'fetch("/' 'fetch("/<yourtunnel_dir>/'; | |
sub_filter_types application/javascript text/html; | |
sub_filter 'modalImage.src = "/' 'modalImage.src = "/<yourtunnel_dir>/'; | |
sub_filter 'url: "/' 'url: "/<yourtunnel_dir>/'; | |
sub_filter 'window.location="/' 'window.location="/<yourtunnel_dir>/'; | |
# Ensure sub_filter is applied to HTML files | |
# sub_filter_types text/html; | |
sub_filter_types text/html application/javascript; | |
# Ensure proper redirects under subdirectory | |
proxy_redirect / /<yourtunnel_dir>/; | |
# proxy_redirect off; | |
proxy_buffering off; | |
# Authentication for this subdirectory | |
limit_req zone=mylimit; | |
auth_basic "Restricted Access"; | |
auth_basic_user_file /etc/nginx/.htpasswd; | |
} | |
# Serve API requests via proxy pass | |
location /api/ { | |
# limit_req zone=mylimit; | |
auth_basic "Restricted Access"; | |
auth_basic_user_file /etc/nginx/.htpasswd; | |
proxy_pass http://127.0.0.1:<remote_port>/api/; | |
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment