From 6adf98886700b90e4cdba879b234ca8fc2e53288 Mon Sep 17 00:00:00 2001 From: Oliver Ni Date: Mon, 6 Apr 2026 05:04:15 -0700 Subject: [PATCH] feat(ocf_www): move nginx to 80/443, apache to backend-only --- modules/ocf_www/files/build-vhosts | 21 ++-- modules/ocf_www/files/vhost-web-nginx.jinja | 27 +++-- modules/ocf_www/files/vhost-web.jinja | 32 ++---- modules/ocf_www/manifests/init.pp | 20 ++-- modules/ocf_www/manifests/nginx.pp | 7 +- modules/ocf_www/manifests/nginx/firewall.pp | 12 --- .../manifests/site/ocfweb_redirects.pp | 101 +----------------- modules/ocf_www/manifests/site/shorturl.pp | 30 +----- modules/ocf_www/manifests/site/unavailable.pp | 19 +--- modules/ocf_www/manifests/site/www.pp | 69 +----------- 10 files changed, 62 insertions(+), 276 deletions(-) delete mode 100644 modules/ocf_www/manifests/nginx/firewall.pp diff --git a/modules/ocf_www/files/build-vhosts b/modules/ocf_www/files/build-vhosts index 028e61d35..1226a7bfe 100755 --- a/modules/ocf_www/files/build-vhosts +++ b/modules/ocf_www/files/build-vhosts @@ -417,15 +417,18 @@ def main(): web_vhosts = get_vhosts() - # Apache config (existing behavior) + # Exclude web vhosts that overlap with app vhosts (app vhosts + # take priority and are proxied directly to apphost by nginx) + web_only_vhosts = { + domain: conf + for domain, conf in web_vhosts.items() + if domain not in prod_app_vhosts + } + + # Apache config (web-only vhosts; apphost vhosts are proxied + # directly by nginx and don't need Apache backend vhosts) apache_config = build_config( - prod_app_vhosts, - jinja_env.get_template('vhost-web.jinja'), - dev_config=args.dev, - ) - apache_config += '\n\n' - apache_config += build_config( - web_vhosts, + web_only_vhosts, jinja_env.get_template('vhost-web.jinja'), dev_config=args.dev, ) @@ -438,7 +441,7 @@ def main(): ) nginx_config += '\n\n' nginx_config += build_config( - web_vhosts, + web_only_vhosts, jinja_env.get_template('vhost-web-nginx.jinja'), dev_config=args.dev, ) diff --git a/modules/ocf_www/files/vhost-web-nginx.jinja b/modules/ocf_www/files/vhost-web-nginx.jinja index d341fd41a..32a67b068 100644 --- a/modules/ocf_www/files/vhost-web-nginx.jinja +++ b/modules/ocf_www/files/vhost-web-nginx.jinja @@ -1,10 +1,9 @@ # {{vhost.comment}} -# CR-soon oliverni: move to 80/443 {% if vhost.ssl %} server { - listen 8443 ssl http2; - listen [::]:8443 ssl http2; + listen 443 ssl http2; + listen [::]:443 ssl http2; server_name "{{vhost.fqdn}}"; ssl_certificate {{vhost.ssl.bundle}}; @@ -32,15 +31,28 @@ server { {% endif %} } + {% for ws_location in vhost.websocket_locations %} + location /{{ws_location}} { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:{{backend_port}}; + } + {% endfor %} + access_log /var/log/nginx/vhost-access.log vhost; } {% endif %} -{% if not vhost.ssl or vhost.is_redirect %} +{% if not vhost.ssl %} # HTTP (redirect or non-SSL) server { - listen 8080; - listen [::]:8080; + listen 80; + listen [::]:80; server_name "{{vhost.fqdn}}"; location /.well-known/ { @@ -50,12 +62,11 @@ server { location / { {% if vhost.is_redirect %} return {{vhost.redirect_type}} {{vhost.redirect_dest}}$request_uri; - {% elif vhost.ssl %} - return 301 {{vhost.canonical_url}}$request_uri; {% else %} proxy_pass http://127.0.0.1:{{backend_port}}; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; {% endif %} } diff --git a/modules/ocf_www/files/vhost-web.jinja b/modules/ocf_www/files/vhost-web.jinja index 2478fb069..5d4dc3692 100644 --- a/modules/ocf_www/files/vhost-web.jinja +++ b/modules/ocf_www/files/vhost-web.jinja @@ -1,35 +1,17 @@ +{% if not vhost.is_redirect %} # {{vhost.comment}} -{% set ports = [vhost.port, backend_port] if vhost.ssl else [vhost.port] %} -{% for port in ports %} - + ServerName {{vhost.fqdn}} ServerAdmin {{vhost.contact_email}} - {% if vhost.ssl and port != backend_port %} - # SSL - SSLEngine on - SSLCertificateFile {{vhost.ssl.bundle}} - SSLCertificateKeyFile {{vhost.ssl.key}} - Protocols h2 http/1.1 - {% endif %} + # Trust X-Forwarded-Proto from nginx so %{HTTPS} works in .htaccess + SetEnvIf X-Forwarded-Proto "https" HTTPS=on - {% if vhost.is_redirect %} - RewriteEngine on - RewriteCond %{REQUEST_URI} !^/\.well-known/ - # 301 redirects are more correct, but get cached forever by dumb browsers. - # Doesn't matter too much for vhosts. - RewriteRule ^(.*)$ {{vhost.redirect_dest}}$1 [L,R={{vhost.redirect_type}}] - {% elif vhost.is_apphost %} - RequestHeader set X-Forwarded-Proto https - ProxyPreserveHost On - SSLProxyEngine on - # Proxy to apphost server - ProxyPass / https://apphost.ocf.berkeley.edu/ upgrade=websocket - {% elif vhost.disabled %} + {% if vhost.disabled %} # Proxy to the local "unavailable" vhost, which serves up a friendly # "your website is rekt" page. RequestHeader set Host unavailable.ocf.berkeley.edu - ProxyPass / http://127.0.0.1/ + ProxyPass / http://127.0.0.1:{{backend_port}}/ {% else %} DocumentRoot {{vhost.docroot}} @@ -61,4 +43,4 @@ UserDir disabled -{% endfor %} +{% endif %} diff --git a/modules/ocf_www/manifests/init.pp b/modules/ocf_www/manifests/init.pp index 082ffb21d..70206bd2c 100644 --- a/modules/ocf_www/manifests/init.pp +++ b/modules/ocf_www/manifests/init.pp @@ -12,12 +12,18 @@ # www.ocf.berkeley.edu, which is by far the most complicated domain. # # Nginx sits in front of Apache for slowloris protection. -# CR-soon oliverni: swap nginx to 80/443, apache to 127.0.0.1:$backend_port only +# Nginx handles 80/443, Apache only listens on 127.0.0.1:$backend_port. class ocf_www { # Port Apache listens on as nginx's backend (plain HTTP on localhost). # Must match BACKEND_PORT in build-vhosts. - # Phase 2: make this the only Apache port and bind to 127.0.0.1. $backend_port = 16767 + + # All Apache vhosts are backend-only (nginx handles 80/443). + Apache::Vhost { + ip => '127.0.0.1', + port => $backend_port, + } + include ocf::acct include ocf::extrapackages include ocf::firewall::allow_web @@ -25,15 +31,12 @@ include ocf::tmpfs include ocf::ssl::default - # enables the http2 module - apache::mod { 'http2': } - class { 'ocf::nfs': cron => false, web => false, } - # nginx reverse proxy (test ports for now) + # nginx reverse proxy include ocf_www::nginx class { @@ -66,8 +69,9 @@ backport_on => 'stretch'; } - # Restart apache if any cert changes occur - Class['ocf::ssl::default'] ~> Class['Apache::Service'] + # Apache no longer serves SSL directly (nginx handles it), but mod_ssl is + # still needed for SSLProxyEngine (outbound HTTPS to apphost). + include apache::mod::ssl include ocf_www::lets_encrypt include ocf_www::logging diff --git a/modules/ocf_www/manifests/nginx.pp b/modules/ocf_www/manifests/nginx.pp index 0c13416b9..bfc847481 100644 --- a/modules/ocf_www/manifests/nginx.pp +++ b/modules/ocf_www/manifests/nginx.pp @@ -1,15 +1,12 @@ # Nginx reverse proxy in front of Apache for slowloris protection. -# CR-soon oliverni: move to 80/443, put apache on 127.0.0.1:$backend_port # # Static vhosts (www, shorturl, etc.) are defined here. # Dynamic user vhosts come from build-vhosts via /etc/nginx/ocf-vhost.conf. class ocf_www::nginx { include ocf::ssl::default - include ocf_www::nginx::firewall - # CR-soon oliverni: change listen/ssl ports to 80/443 - $http_port = 8080 - $ssl_port = 8443 + $http_port = 80 + $ssl_port = 443 $backend = "http://127.0.0.1:${ocf_www::backend_port}" diff --git a/modules/ocf_www/manifests/nginx/firewall.pp b/modules/ocf_www/manifests/nginx/firewall.pp deleted file mode 100644 index cc879903e..000000000 --- a/modules/ocf_www/manifests/nginx/firewall.pp +++ /dev/null @@ -1,12 +0,0 @@ -# CR-soon oliverni: remove when nginx moves to 80/443 -class ocf_www::nginx::firewall { - ocf::firewall::firewall46 { - '101 allow nginx test ports': - opts => { - chain => 'PUPPET-INPUT', - proto => 'tcp', - dport => [8080, 8443], - action => 'accept', - }; - } -} diff --git a/modules/ocf_www/manifests/site/ocfweb_redirects.pp b/modules/ocf_www/manifests/site/ocfweb_redirects.pp index c00bf6feb..e22ae8556 100644 --- a/modules/ocf_www/manifests/site/ocfweb_redirects.pp +++ b/modules/ocf_www/manifests/site/ocfweb_redirects.pp @@ -2,11 +2,6 @@ # redirect those sites to the appropriate pages on ocfweb. class ocf_www::site::ocfweb_redirects { # accounts - $accounts_canonical_url = $::host_env ? { - 'dev' => 'https://dev-accounts.ocf.berkeley.edu/', - 'prod' => 'https://accounts.ocf.berkeley.edu/', - } - $accounts_options = { servername => 'accounts.ocf.berkeley.edu', serveraliases => ['dev-accounts.ocf.berkeley.edu'], @@ -21,42 +16,11 @@ ], } - apache::vhost { 'accounts': - * => $accounts_options, - port => 443, - ssl => true, - headers => ['always set Strict-Transport-Security max-age=31536000'], - ssl_key => "/etc/ssl/private/${::fqdn}.key", - ssl_cert => "/etc/ssl/private/${::fqdn}.crt", - ssl_chain => "/etc/ssl/private/${::fqdn}.intermediate", - } - - # nginx backend (plain HTTP on localhost) apache::vhost { 'accounts-backend': - * => $accounts_options, - port => $ocf_www::backend_port, - } - - apache::vhost { 'accounts-http-redirect': - servername => 'accounts.ocf.berkeley.edu', - serveraliases => [ - 'dev-accounts', - 'dev-accounts.ocf.berkeley.edu', - 'accounts', - ], - port => 80, - docroot => '/var/www/html', - - redirect_status => 'permanent', - redirect_dest => $accounts_canonical_url; + * => $accounts_options, } # wiki - $wiki_canonical_url = $::host_env ? { - 'dev' => 'https://dev-wiki.ocf.berkeley.edu/', - 'prod' => 'https://wiki.ocf.berkeley.edu/', - } - $wiki_options = { servername => 'wiki.ocf.berkeley.edu', serveraliases => ['dev-wiki.ocf.berkeley.edu'], @@ -67,42 +31,11 @@ ], } - apache::vhost { 'wiki': - * => $wiki_options, - port => 443, - ssl => true, - headers => ['always set Strict-Transport-Security max-age=31536000'], - ssl_key => "/etc/ssl/private/${::fqdn}.key", - ssl_cert => "/etc/ssl/private/${::fqdn}.crt", - ssl_chain => "/etc/ssl/private/${::fqdn}.intermediate", - } - - # nginx backend (plain HTTP on localhost) apache::vhost { 'wiki-backend': - * => $wiki_options, - port => $ocf_www::backend_port, - } - - apache::vhost { 'wiki-http-redirect': - servername => 'wiki.ocf.berkeley.edu', - serveraliases => [ - 'dev-wiki', - 'dev-wiki.ocf.berkeley.edu', - 'wiki', - ], - port => 80, - docroot => '/var/www/html', - - redirect_status => 'permanent', - redirect_dest => $wiki_canonical_url; + * => $wiki_options, } # hello - $hello_canonical_url = $::host_env ? { - 'dev' => 'https://dev-hello.ocf.berkeley.edu/', - 'prod' => 'https://hello.ocf.berkeley.edu/', - } - $hello_options = { servername => 'hello.ocf.berkeley.edu', serveraliases => [ @@ -118,35 +51,7 @@ ], } - apache::vhost { 'hello': - * => $hello_options, - port => 443, - ssl => true, - headers => ['always set Strict-Transport-Security max-age=31536000'], - ssl_key => "/etc/ssl/private/${::fqdn}.key", - ssl_cert => "/etc/ssl/private/${::fqdn}.crt", - ssl_chain => "/etc/ssl/private/${::fqdn}.intermediate", - } - - # nginx backend (plain HTTP on localhost) apache::vhost { 'hello-backend': - * => $hello_options, - port => $ocf_www::backend_port, - } - - apache::vhost { 'hello-http-redirect': - servername => 'hello.ocf.berkeley.edu', - serveraliases => [ - 'dev-hello', - 'dev-hello.ocf.berkeley.edu', - 'dev-staff.ocf.berkeley.edu', - 'hello', - 'staff.ocf.berkeley.edu', - ], - port => 80, - docroot => '/var/www/html', - - redirect_status => 'permanent', - redirect_dest => $hello_canonical_url; + * => $hello_options, } } diff --git a/modules/ocf_www/manifests/site/shorturl.pp b/modules/ocf_www/manifests/site/shorturl.pp index 7a6070d66..28eeed9e0 100644 --- a/modules/ocf_www/manifests/site/shorturl.pp +++ b/modules/ocf_www/manifests/site/shorturl.pp @@ -1,9 +1,4 @@ class ocf_www::site::shorturl { - $canonical_url = $::host_env ? { - 'dev' => 'https://dev-ocf-io.ocf.berkeley.edu/', - 'prod' => 'https://ocf.io/', - } - $shorturl_options = { servername => 'ocf.io', serveraliases => ['dev-ocf-io.ocf.berkeley.edu', 'www.ocf.io'], @@ -171,30 +166,7 @@ ], } - apache::vhost { 'shorturl': - * => $shorturl_options, - port => 443, - ssl => true, - headers => ['always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"'], - ssl_key => "/etc/ssl/private/${::fqdn}.key", - ssl_cert => "/etc/ssl/private/${::fqdn}.crt", - ssl_chain => "/etc/ssl/private/${::fqdn}.intermediate", - } - - # nginx backend (plain HTTP on localhost) apache::vhost { 'shorturl-backend': - * => $shorturl_options, - port => $ocf_www::backend_port, - } - - # canonical redirects - apache::vhost { 'shorturl-http-redirect': - servername => 'ocf.io', - serveraliases => ['dev-ocf-io.ocf.berkeley.edu', 'www.ocf.io'], - port => 80, - docroot => '/var/www/html', - - redirect_status => 'permanent', - redirect_dest => $canonical_url; + * => $shorturl_options, } } diff --git a/modules/ocf_www/manifests/site/unavailable.pp b/modules/ocf_www/manifests/site/unavailable.pp index 1df51cabc..aa939db0c 100644 --- a/modules/ocf_www/manifests/site/unavailable.pp +++ b/modules/ocf_www/manifests/site/unavailable.pp @@ -39,24 +39,7 @@ ], } - apache::vhost { 'unavailable': - * => $options, - port => 80, - } - - apache::vhost { 'https-unavailable': - * => $options, - port => 443, - - ssl => true, - ssl_key => "/etc/ssl/private/${::fqdn}.key", - ssl_cert => "/etc/ssl/private/${::fqdn}.crt", - ssl_chain => "/etc/ssl/private/${::fqdn}.intermediate", - } - - # nginx backend (plain HTTP on localhost) apache::vhost { 'unavailable-backend': - * => $options, - port => $ocf_www::backend_port, + * => $options, } } diff --git a/modules/ocf_www/manifests/site/www.pp b/modules/ocf_www/manifests/site/www.pp index 7abd0b732..03a7b7fdc 100644 --- a/modules/ocf_www/manifests/site/www.pp +++ b/modules/ocf_www/manifests/site/www.pp @@ -97,11 +97,6 @@ ], allow_override => ['All'], }, - { - path => '\.(cgi|shtml|phtml|php)$', - provider => 'filesmatch', - ssl_options => '+StdEnvVars', - }, { path => '\.(php[3457]?|phtml|fcgi)$', provider => 'filesmatch', @@ -117,27 +112,16 @@ ], custom_fragment => ' - Protocols h2 http/1.1 + # Trust X-Forwarded-Proto from nginx so %{HTTPS} works in userdirs + SetEnvIf X-Forwarded-Proto "https" HTTPS=on + UserDir /services/http/users/ UserDir disabled root ', } - apache::vhost { 'www': - * => $www_options, - port => 443, - ssl => true, - ssl_key => "/etc/ssl/private/${::fqdn}.key", - ssl_cert => "/etc/ssl/private/${::fqdn}.crt", - ssl_chain => "/etc/ssl/private/${::fqdn}.intermediate", - headers => ['always set Strict-Transport-Security max-age=31536000'], - request_headers => ['set X-Forwarded-Proto https'], - } - - # nginx backend (plain HTTP on localhost) apache::vhost { 'www-backend': - * => $www_options, - port => $ocf_www::backend_port, + * => $www_options, } # canonical redirects @@ -146,38 +130,6 @@ 'prod' => 'https://www.ocf.berkeley.edu$1', } - apache::vhost { - # redirect HTTP -> canonical HTTPS - 'www-http-redirect': - servername => 'www.ocf.berkeley.edu', - serveraliases => [ - 'www', - 'dev-www', - 'dev-www.ocf.berkeley.edu', - 'ocf.berkeley.edu', - 'dev-ocf.berkeley.edu', - 'secure', - 'secure.ocf.berkeley.edu', - 'ocf.asuc.org', - - # Domains we don't actually use, but want to redirect to our home page - # (rather than show the 503 unavailable error). - 'death.berkeley.edu', - 'linux.berkeley.edu', - - $::hostname, - $::fqdn, - ], - port => 80, - docroot => '/var/www/html', - redirectmatch_status => '301', - # ugly exceptions - redirectmatch_regexp => '^((?!\/\.well-known\/matrix\/(client|server)).*)', - redirectmatch_dest => $canonical_url; - - } - - # redirect weird HTTPS -> canonical HTTPS $https_redirect_options = { servername => 'ocf.berkeley.edu', serveraliases => [ @@ -201,18 +153,7 @@ redirectmatch_dest => $canonical_url, } - apache::vhost { 'www-https-redirect': - * => $https_redirect_options, - port => 443, - ssl => true, - ssl_key => "/etc/ssl/private/${::fqdn}.key", - ssl_cert => "/etc/ssl/private/${::fqdn}.crt", - ssl_chain => "/etc/ssl/private/${::fqdn}.intermediate", - } - - # nginx backend (plain HTTP on localhost) apache::vhost { 'www-https-redirect-backend': - * => $https_redirect_options, - port => $ocf_www::backend_port, + * => $https_redirect_options, } }