-VPS_HOST=dev.nutra.tk
+VPS_HOST_DEV=dev.nutra.tk
+VPS_HOST_PROD=nutra.tk
+VPS_HOST=$(VPS_HOST_DEV)
+#VPS_HOST=$(VPS_HOST_PROD)
VPS_USER=gg
export SUDO_USER=gg
export OWNER="Shane J"
VPS := $(VPS_USER)@$(VPS_HOST)
+# Detect Environment
+ifeq ($(VPS_HOST),$(VPS_HOST_DEV))
+ ENV := dev
+else ifeq ($(VPS_HOST),$(VPS_HOST_PROD))
+ ENV := prod
+else
+ ENV := dev
+endif
+
.PHONY: stage/nginx
stage/nginx: ##H @Remote Stage files on the remote VPS
- @echo "Staging files on $(VPS_HOST)..."
+ @echo "Staging files on $(VPS_HOST) (ENV=$(ENV))..."
python3 scripts/gen_services_map.py
ssh $(VPS) 'rm -rf ~/.nginx-staging && mkdir -p ~/.nginx-staging/etc/nginx/conf.d ~/.nginx-staging/scripts/gitweb-simplefrontend'
scp -q -r etc/nginx/conf.d/*.conf $(VPS):~/.nginx-staging/etc/nginx/conf.d/
deploy/nginx: ##H @Remote Deploy staged files to remote
deploy/nginx: stage/nginx test/nginx diff/nginx
@echo "Deploying checked-in nginx config to $(VPS_HOST)..."
- ssh -t $(VPS) "bash ~/.nginx-staging/scripts/deploy.sh"
+ ssh -t $(VPS) "bash ~/.nginx-staging/scripts/deploy.sh $(ENV)"
.PHONY: test/nginx
test/nginx: ##H @Remote Test staged configuration without deploying
+++ /dev/null
-# API
-server {
- # Service: API | https://api.dev.nutra.tk
- server_name api-dev.nutra.tk api.dev.nutra.tk;
- #listen 80;
- listen 443 ssl;
- listen 443 quic;
- listen [::]:443 quic;
- http2 on;
- http3 on;
- add_header Alt-Svc 'h3=":443"; ma=86400' always;
- # HSTS
- add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
-
- # Sanic
- location / {
- proxy_pass http://127.0.0.1:20000; # API server
- # Allow fast streaming HTTP/1.1 pipes (keep-alive, unbuffered)
- proxy_http_version 1.1;
- proxy_request_buffering off;
- proxy_buffering off;
- # Proxy forwarding (password configured in app.config.FORWARDED_SECRET)
- # and stored in: /etc/nginx/conf.d/secrets.conf
- proxy_set_header forwarded "$proxy_forwarded;secret=\"$proxy_secret_key\"";
- # Allow websockets and keep-alive (avoid connection: close)
- proxy_set_header connection "upgrade";
- proxy_set_header upgrade $http_upgrade;
- }
-
- # default favicon
- location /favicon.ico {
- alias /var/www/favicon.gif;
- }
-}
-
-
-# Store Front (MedusaJS)
-server {
- # Service: Store | https://store.nutra.tk
- server_name store.nutra.tk;
- #listen 80;
- listen 443 ssl;
- listen 443 quic;
- listen [::]:443 quic;
- http2 on;
- http3 on;
- add_header Alt-Svc 'h3=":443"; ma=86400' always;
- location / {
- proxy_pass http://localhost:8000;
- }
-}
-
-# Store [Admin UI] (MedusaJS)
-server {
- # Service: Store Admin | https://store-admin-8b56411b.nutra.tk
- server_name store-api.nutra.tk store-admin-8b56411b.nutra.tk;
- #listen 80;
- listen 443 ssl;
- listen 443 quic;
- listen [::]:443 quic;
- http2 on;
- http3 on;
- add_header Alt-Svc 'h3=":443"; ma=86400' always;
- location / {
- proxy_pass http://localhost:9000;
- }
-}
-
-
-# UI, blog, favicon, default server
-server {
- server_name dev.nutra.tk;
-
- # HTTP/3 (QUIC) - UDP
- listen 443 quic reuseport default_server;
- listen [::]:443 quic reuseport default_server;
-
- # HTTP/2 & 1.1 (Fallback) - TCP
- listen 443 ssl default_server;
- listen [::]:443 ssl default_server;
-
- # Enable protocols
- http2 on;
- http3 on;
-
- # Advertise HTTP/3 availability
- add_header Alt-Svc 'h3=":443"; ma=86400' always;
-
- client_max_body_size 50m;
-
- # HSTS
- add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
- ssl_trusted_certificate /etc/ssl/private/ca-certs.pem;
- # OCSP stapling (NOTE: Responders disabled by letsencrypt as of Q3 2025)
- #ssl_stapling on;
- #ssl_stapling_verify on;
-
- # Services Map (Homepage)
- location / {
- alias /var/www/homepage.html;
- default_type text/html;
- }
-
-# # Blog / Sphinx
-# location /blog {
-# alias /var/www/blog;
-# index index.html;
-# }
-
- # default favicon
- location = /favicon.ico {
- alias /var/www/favicon.gif;
- }
-
- # Other
- location ~ /.well-known {
- allow all;
- }
-
- # CV paths
- location ~ ^/cv/(~?swe|swe~/resume\.pdf)$ {
- alias /var/www/cv/swe/resume.pdf;
- default_type application/pdf;
- }
- location ~ ^/resume(\.pdf|/swe\.pdf)$ {
- alias /var/www/cv/swe/resume.pdf;
- default_type application/pdf;
- }
-
- # public folder
- location /public {
- root /var/www;
- autoindex on;
- #index index.html index.htm;
- #try_files $uri $uri/ /index.html =404;
- }
-
- # HTTPS / SSL
- ssl_certificate /etc/letsencrypt/live/dev.nutra.tk/fullchain.pem; # managed by Certbot
- ssl_certificate_key /etc/letsencrypt/live/dev.nutra.tk/privkey.pem; # managed by Certbot
- include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
-}
-
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Redirect www.dev.nutra.tk -> dev.nutra.tk
-server {
- listen 443 ssl;
- listen 443 quic;
- listen [::]:443 quic;
- http2 on;
- http3 on;
- server_name www.dev.nutra.tk;
-
- ssl_certificate /etc/letsencrypt/live/dev.nutra.tk/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/dev.nutra.tk/privkey.pem;
- include /etc/letsencrypt/options-ssl-nginx.conf;
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
-
- return 301 https://dev.nutra.tk$request_uri;
-}
-
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Listen on 443 with matrix / synapse
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-server {
- listen 443 ssl;
- listen 443 quic;
- http2 on;
- http3 on;
- add_header Alt-Svc 'h3=":443"; ma=86400' always;
- server_name matrix.nutra.tk chat.nutra.tk;
-
- location / {
- # Service: Matrix Chat | https://chat.nutra.tk
- proxy_pass http://127.0.0.1:8008;
- proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
- proxy_set_header X-Forwarded-For $remote_addr;
- }
-
- location /favicon.ico {
- alias /var/www/favicon.gif;
- }
-}
-
-# Open matrix chat on 8448
-server {
- listen 8448 ssl default_server;
- listen [::]:8448 ssl default_server;
- server_name dev.nutra.tk;
-
- location / {
- proxy_pass http://127.0.0.1:8008;
- proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
- proxy_set_header X-Forwarded-For $remote_addr;
- }
-
- # HTTPS / SSL
- ssl_certificate /etc/letsencrypt/live/dev.nutra.tk/fullchain.pem; # managed by Certbot
- ssl_certificate_key /etc/letsencrypt/live/dev.nutra.tk/privkey.pem; # managed by Certbot
- include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
-}
+# Redirect all HTTP to HTTPS with no-WWW
+server {
+ listen 80 default_server;
+ listen [::]:80 default_server;
+ server_name ~^(?:www\.)?(.*)$;
+ return 301 https://$1$request_uri;
+}
+
# API
server {
- # Service: API | https://api.dev.nutra.tk
- server_name api-dev.nutra.tk api.dev.nutra.tk;
+ # Service: API | https://api.nutra.tk
+ server_name api.nutra.tk;
#listen 80;
listen 443 ssl;
listen 443 quic;
# UI, blog, favicon, default server
server {
- server_name dev.nutra.tk;
+ server_name nutra.tk;
# HTTP/3 (QUIC) - UDP
listen 443 quic reuseport default_server;
allow all;
}
- # CV paths
- location ~ ^/cv/(~?swe|swe~/resume\.pdf)$ {
- alias /var/www/cv/swe/resume.pdf;
- default_type application/pdf;
- }
- location ~ ^/resume(\.pdf|/swe\.pdf)$ {
- alias /var/www/cv/swe/resume.pdf;
- default_type application/pdf;
+ # CV paths - Redirect to Dev (only hosted there)
+ location ~ ^/(cv/(~?swe|swe~/resume\.pdf)|resume(\.pdf|/swe\.pdf))$ {
+ return 301 https://dev.$server_name/resume.pdf;
}
# public folder
}
# HTTPS / SSL
- ssl_certificate /etc/letsencrypt/live/dev.nutra.tk/fullchain.pem; # managed by Certbot
- ssl_certificate_key /etc/letsencrypt/live/dev.nutra.tk/privkey.pem; # managed by Certbot
+ ssl_certificate /etc/letsencrypt/live/nutra.tk/fullchain.pem; # managed by Certbot
+ ssl_certificate_key /etc/letsencrypt/live/nutra.tk/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Redirect www.dev.nutra.tk -> dev.nutra.tk
+# Redirect www.nutra.tk -> nutra.tk
server {
listen 443 ssl;
listen 443 quic;
listen [::]:443 quic;
http2 on;
http3 on;
- server_name www.dev.nutra.tk;
+ server_name www.nutra.tk;
- ssl_certificate /etc/letsencrypt/live/dev.nutra.tk/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/dev.nutra.tk/privkey.pem;
+ ssl_certificate /etc/letsencrypt/live/nutra.tk/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/nutra.tk/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
- return 301 https://dev.nutra.tk$request_uri;
+ return 301 https://nutra.tk$request_uri;
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
server {
listen 8448 ssl default_server;
listen [::]:8448 ssl default_server;
- server_name dev.nutra.tk;
+ server_name nutra.tk;
location / {
proxy_pass http://127.0.0.1:8008;
}
# HTTPS / SSL
- ssl_certificate /etc/letsencrypt/live/dev.nutra.tk/fullchain.pem; # managed by Certbot
- ssl_certificate_key /etc/letsencrypt/live/dev.nutra.tk/privkey.pem; # managed by Certbot
+ ssl_certificate /etc/letsencrypt/live/nutra.tk/fullchain.pem; # managed by Certbot
+ ssl_certificate_key /etc/letsencrypt/live/nutra.tk/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
fi
[ -f /etc/gitweb.conf ] && sudo cp /etc/gitweb.conf "$BACKUP_DIR/gitweb.conf"
+# ENV is passed as first argument if not diff/test, default to dev
+ENV="${1:-dev}"
+echo "Deploying for environment: $ENV"
+
echo "Installing new configurations..."
for FILE in "$NGINX_CONF_SRC"/*.conf; do
BASENAME=$(basename "$FILE")
+
+ # Skip encrypted secrets
if [ "$BASENAME" = "secrets.conf" ] && ! is_text_file "$FILE"; then
echo "Skipping encrypted secrets.conf..."
continue
fi
- sudo cp "$FILE" "$DEST_CONF_DIR/"
+
+ # Handle default configuration switching
+ if [[ "$BASENAME" == "default.dev.conf" || "$BASENAME" == "default.prod.conf" || "$BASENAME" == "default.conf" ]]; then
+ if [ "$BASENAME" == "default.${ENV}.conf" ]; then
+ echo "Installing $BASENAME as default.conf..."
+ sudo cp "$FILE" "$DEST_CONF_DIR/default.conf"
+ else
+ # Skip other environment configs and the raw default.conf if it exists
+ echo "Skipping mismatch/raw config: $BASENAME"
+ continue
+ fi
+ else
+ # Install all other configs as-is
+ sudo cp "$FILE" "$DEST_CONF_DIR/"
+ fi
done
echo "Verifying configuration..."
services_git = parse_file(NGINX_CONF, version_pattern, is_version=True)
- DEFAULT_CONF = REPO_ROOT / "etc/nginx/conf.d/default.conf"
+ # Locate default.conf
+ # On Server: Read the live deployed config
+ live_default = Path("/etc/nginx/conf.d/default.conf")
+ # On Local: Read default.dev.conf
+ local_dev = REPO_ROOT / "etc/nginx/conf.d/default.dev.conf"
+
+ if live_default.exists():
+ DEFAULT_CONF = live_default
+ print(f"Using live config: {DEFAULT_CONF}")
+ else:
+ DEFAULT_CONF = local_dev
+ print(f"Using local config: {DEFAULT_CONF}")
+
services_other = parse_file(DEFAULT_CONF, service_pattern, is_version=False)
return services_git, services_other