From 5cc67b9347ff4bf081076e60fe52b196a17a245e Mon Sep 17 00:00:00 2001 From: Yan Lin Date: Mon, 8 Sep 2025 21:23:59 +0200 Subject: [PATCH] Add VPS reverse proxy services --- hosts/nixos/vps/containers.nix | 58 ++++++++++++++++++++++++++ hosts/nixos/vps/proxy.nix | 76 ++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/hosts/nixos/vps/containers.nix b/hosts/nixos/vps/containers.nix index d76cf94..a4318ab 100644 --- a/hosts/nixos/vps/containers.nix +++ b/hosts/nixos/vps/containers.nix @@ -1,7 +1,65 @@ { config, pkgs, lib, ... }: +let + # Universal container configuration + commonUID = "1000"; + commonGID = "100"; + systemTZ = config.time.timeZone; +in { # Container definitions for vps host virtualisation.oci-containers.containers = { + # Static web server for homepage + homepage = { + image = "docker.io/nginx:alpine"; + + volumes = [ + "/home/yanlin/www/homepage:/usr/share/nginx/html:ro" + "/home/yanlin/www/homepage-nginx.conf:/etc/nginx/conf.d/default.conf:ro" + ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.homepage.rule" = "Host(`www.yanlincs.com`)"; + "traefik.http.routers.homepage.entrypoints" = "websecure"; + "traefik.http.routers.homepage.tls" = "true"; + "traefik.http.routers.homepage.tls.certresolver" = "cloudflare"; + "traefik.http.routers.homepage.tls.domains[0].main" = "yanlincs.com"; + "traefik.http.routers.homepage.tls.domains[0].sans[0]" = "*.yanlincs.com"; + "traefik.http.services.homepage.loadbalancer.server.port" = "80"; + }; + + extraOptions = [ + "--network=podman" + ]; + + autoStart = true; + }; + + # Static web server for blog + blog = { + image = "docker.io/nginx:alpine"; + + volumes = [ + "/home/yanlin/www/blog:/usr/share/nginx/html:ro" + "/home/yanlin/www/blog-nginx.conf:/etc/nginx/conf.d/default.conf:ro" + ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.blog.rule" = "Host(`blog.yanlincs.com`)"; + "traefik.http.routers.blog.entrypoints" = "websecure"; + "traefik.http.routers.blog.tls" = "true"; + "traefik.http.routers.blog.tls.certresolver" = "cloudflare"; + "traefik.http.routers.blog.tls.domains[0].main" = "*.yanlincs.com"; + "traefik.http.services.blog.loadbalancer.server.port" = "80"; + }; + + extraOptions = [ + "--network=podman" + ]; + + autoStart = true; + }; }; } diff --git a/hosts/nixos/vps/proxy.nix b/hosts/nixos/vps/proxy.nix index d2b0586..b0edeae 100644 --- a/hosts/nixos/vps/proxy.nix +++ b/hosts/nixos/vps/proxy.nix @@ -5,8 +5,84 @@ services.traefik.dynamicConfigOptions = { http = { routers = { + # Redirect from yanlincs.com to www.yanlincs.com + homepage-redirect = { + rule = "Host(`yanlincs.com`)"; + entrypoints = "websecure"; + service = "homepage-redirect"; + middlewares = [ "homepage-redirect" ]; + tls = { + certResolver = "cloudflare"; + domains = [{ + main = "yanlincs.com"; + sans = [ "www.yanlincs.com" ]; + }]; + }; + }; + + # Photo service (Immich) + photo = { + rule = "Host(`photo.yanlincs.com`)"; + entrypoints = "websecure"; + service = "photo"; + tls = { + certResolver = "cloudflare"; + domains = [{ + main = "*.yanlincs.com"; + }]; + }; + }; + + # Cloud service (Nextcloud) + cloud = { + rule = "Host(`cloud.yanlincs.com`)"; + entrypoints = "websecure"; + service = "cloud"; + tls = { + certResolver = "cloudflare"; + domains = [{ + main = "*.yanlincs.com"; + }]; + }; + }; }; services = { + # Redirect service + homepage-redirect = { + loadBalancer = { + servers = [{ + url = "http://localhost:1"; # Dummy backend, won't be used due to redirect + }]; + }; + }; + + # Photo service backend + photo = { + loadBalancer = { + servers = [{ + url = "http://hs.yanlincs.com:5000"; + }]; + }; + }; + + # Cloud service backend + cloud = { + loadBalancer = { + servers = [{ + url = "http://hs.yanlincs.com:5001"; + }]; + }; + }; + }; + middlewares = { + # Redirect middleware + homepage-redirect = { + redirectRegex = { + regex = "^https://yanlincs\\.com/(.*)"; + replacement = "https://www.yanlincs.com/$1"; + permanent = true; + }; + }; }; }; };