From 97b5b78976cb5c1d26e91b7716d719807cd58195 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Mon, 9 Nov 2026 10:04:16 +0000 Subject: [PATCH] dev2-edge: route unrouted Moshpit names to the c0mpute edge Every label.ending SNI with no route of its own and an ending that is not an IANA TLD goes to moshpit-proxy's c0mpute edge on 127.0.0.1:8456, which serves c0mpute sites and splices every other connection back to nginx :8444. Real TLDs are wildcard entries from dev2/edge/iana-tlds.txt, so no ICANN apex takes the hop. Port 80 gains a regex server proxying the same names to the edge's http port, parking the ones it answers 421 for, exactly as the catch-all did. alt.2600 leaves Caddy: it is now a c0mpute site. Co-Authored-By: Claude Opus 5.5 --- dev2/dev2-edge | 90 ++- dev2/edge/edge-box | 16 +- dev2/edge/edge.json | 3 +- dev2/edge/iana-tlds.txt | 1437 +++++++++++++++++++++++++++++++++++++++ test/dev2-edge.test.ts | 26 + 5 files changed, 1565 insertions(+), 7 deletions(-) create mode 100644 dev2/edge/iana-tlds.txt diff --git a/dev2/dev2-edge b/dev2/dev2-edge index 0ed293f..573598c 100755 --- a/dev2/dev2-edge +++ b/dev2/dev2-edge @@ -16,9 +16,14 @@ How it works (agreed with Anthony 2026-10-19, "pit.world first"): visitor :443 -> nginx stream {} (ssl_preread, SNI only, TLS not terminated) pit.world, *.pit.world, Moshpit names in edge.json -> 127.0.0.1:8453 Caddy everything else -> 127.0.0.1:8444 nginx http - both hops carry a PROXY protocol header, so nginx ($remote_addr via real_ip_header + other Moshpit-shaped names (label.ending, ending not an IANA TLD) + -> c0mpute_edge.tls (moshpit-proxy's c0mpute edge), which terminates the + names the registry says are c0mpute sites and splices every other + connection, PROXY header included, back to 127.0.0.1:8444 + every hop carries a PROXY protocol header, so nginx ($remote_addr via real_ip_header proxy_protocol) and Caddy (proxy_protocol listener wrapper) see the visitor's address. - Port 80 is untouched: nginx keeps answering ACME and http->https for every name. + Port 80 stays on nginx (ACME, http->https). The one addition: Moshpit-shaped names + with no :80 vhost of their own are proxied to the c0mpute edge's plain http port. Certificates are never issued by Caddy (auto_https off). caddy-edge-certs copies what certbot, pit-proxy-cert and moshpit-renew already keep current into bundles Caddy @@ -38,6 +43,7 @@ import datetime as dt import hashlib import json import os +import re import shlex import shutil import subprocess @@ -86,6 +92,32 @@ def stream_pattern(host): return host +TLDS = os.path.join(EDGE, "iana-tlds.txt") + + +def iana_tlds(path=TLDS): + """Every top-level domain IANA delegates (data.iana.org/TLD/tlds-alpha-by-domain.txt).""" + with open(path) as f: + tlds = [l.strip().lower() for l in f if l.strip() and not l.startswith("#")] + if len(tlds) < 1000: + die(f"{path}: only {len(tlds)} TLDs, refusing to treat the rest of the namespace as Moshpit") + return tlds + + +# Moshpit names are label.ending; an ending is never a real TLD. nginx cannot hold a +# negative-lookahead over 1,400 TLDs in one token (4 KiB limit), so the real TLDs are +# map entries (`.com` covers com and *.com, and a wildcard beats any regex) and a short +# regex catches the two-label names left over. +MOSHPIT_NAME_RE = r"~^[a-z0-9-]+\.[a-z0-9-]+$" +TLD_MAP_DIR = "etc/nginx/dev2-edge" + + +def render_tld_map(value): + rows = [HEADER.rstrip("\n"), f"# every IANA TLD ({len(iana_tlds())}), from dev2/edge/iana-tlds.txt: never a Moshpit name"] + rows += [f".{t} {value};" for t in iana_tlds()] + return "\n".join(rows) + "\n" + + def render_stream(s, on=True): p = s["ports"] caddy, nginx = f"127.0.0.1:{p['caddy']}", f"127.0.0.1:{p['nginx']}" @@ -102,13 +134,23 @@ def render_stream(s, on=True): if h.startswith("//"): continue rows.append(f" {h:<32} {nginx}; # {why[:90]}") + ce = s.get("c0mpute_edge") + if ce: + # Last, and a regex: nginx tries exact names and wildcards first, so every + # name listed above (Caddy's Moshpit names included) keeps its route. + rows.append(f" include /{TLD_MAP_DIR}/iana-tlds.stream.map; # real TLDs stay on nginx") + rows.append(" # every other Moshpit name: the c0mpute edge (it splices non-c0mpute names back to nginx)") + rows.append(f' "{MOSHPIT_NAME_RE}" 127.0.0.1:{ce["tls"]};') state = "on: the names below go to Caddy" if on else "off: every name goes to nginx (dev2-edge route off)" return HEADER + f"""# The edge ({state}). # nginx's stream module owns :443. It reads the TLS server name (ssl_preread; the TLS # itself is not terminated here) and passes the connection on, with a PROXY protocol # header carrying the visitor's address, to Caddy or to nginx's own https servers. stream {{ - map $ssl_preread_server_name $dev2_edge_backend {{ +""" + (""" # ~1,500 keys with the real-TLD map: more than the default 2048/64 hash holds. + map_hash_max_size 4096; + map_hash_bucket_size 128; +""" if on and s.get("c0mpute_edge") else "") + f""" map $ssl_preread_server_name $dev2_edge_backend {{ hostnames; default {nginx}; """ + "\n".join(rows) + ("\n" if rows else "") + f""" }} @@ -128,6 +170,44 @@ stream {{ """ +def render_c0mpute_http(s): + ce = s.get("c0mpute_edge") + if not ce: + return None + return HEADER + f"""# Plain http for Moshpit names pointed at c0mpute sites: the c0mpute edge serves them on +# 127.0.0.1:{ce['http']}. A regex server_name, so every name with its own :80 vhost (an +# exact or wildcard server_name) keeps it. Everything else this regex catches gets what +# the port-80 catch-all in userdirs.conf (cli-tools/root-ubuntu.sh) gave it: ACME +# challenges, an https upgrade for a real domain, and parking for a Moshpit name the edge +# says is not a c0mpute site (its 421). $moshpit_parked comes from that tool's +# conf.d/moshpit-parking.conf; without it `nginx -t` fails and apply changes nothing. +server {{ + listen 80; + listen [::]:80; + server_name "{MOSHPIT_NAME_RE}"; + + location ^~ /.well-known/acme-challenge/ {{ + root {ce.get('acme_webroot', '/var/www/acme')}; + default_type "text/plain"; + }} + + location / {{ + if ($moshpit_parked = 0) {{ return 301 https://$host$request_uri; }} + proxy_pass http://127.0.0.1:{ce['http']}; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_http_version 1.1; + proxy_intercept_errors on; + error_page 421 = @parked; + }} + + location @parked {{ + return 302 {ce.get('parking', 'https://pit.moshcode.sh/n/')}$host; + }} +}} +""" + + def render_realip(s): return HEADER + f"""# Every https server listens on 127.0.0.1:{s['ports']['nginx']} behind the edge stream proxy, # which sends the visitor's address in a PROXY protocol header. Without these two lines @@ -242,6 +322,10 @@ def render(out, s, on=True): "etc/caddy/Caddyfile": render_caddyfile(s), "etc/caddy/edge-cert-sources": render_cert_sources(s), } + c0http = render_c0mpute_http(s) + if c0http: + files["etc/nginx/conf.d/c0mpute-edge-http.conf"] = c0http + files[f"{TLD_MAP_DIR}/iana-tlds.stream.map"] = render_tld_map(f"127.0.0.1:{s['ports']['nginx']}") for u in UNITS: with open(os.path.join(EDGE, "systemd", u)) as f: files[f"etc/systemd/system/{u}"] = f.read() diff --git a/dev2/edge/edge-box b/dev2/edge/edge-box index 9eb9fb4..137c0a4 100755 --- a/dev2/edge/edge-box +++ b/dev2/edge/edge-box @@ -30,6 +30,9 @@ BACKUPS = "/home/anthony/backups" NGINX_CONF = "/etc/nginx/nginx.conf" STREAM_DIR = "/etc/nginx/stream-enabled" STREAM_CONF = f"{STREAM_DIR}/dev2-edge.conf" +C0MPUTE_HTTP = "etc/nginx/conf.d/c0mpute-edge-http.conf" +# The real-TLD map the stream map includes, then the :80 server: installed before the stream map. +C0MPUTE_FILES = ["etc/nginx/dev2-edge/iana-tlds.stream.map", C0MPUTE_HTTP] REALIP_CONF = "/etc/nginx/conf.d/00-edge-realip.conf" CF_CONF = "/etc/nginx/conf.d/cloudflare-realip.conf" DROPIN = "/etc/systemd/system/nginx.service.d/dev2-edge.conf" @@ -299,8 +302,9 @@ def apply(bundle): say(f"Caddy on 127.0.0.1:{spec['ports']['caddy']} answers like nginx for {len(checked)} names") # ---- the switch: one nginx reload hands :443 from the http servers to the stream. - install_files(bundle, ["etc/nginx/stream-enabled/dev2-edge.conf", "etc/nginx/conf.d/00-edge-realip.conf", - "etc/systemd/system/nginx.service.d/dev2-edge.conf"]) + install_files(bundle, [f for f in C0MPUTE_FILES if os.path.exists(f"{bundle}/root/{f}")] + + ["etc/nginx/stream-enabled/dev2-edge.conf", "etc/nginx/conf.d/00-edge-realip.conf", + "etc/systemd/system/nginx.service.d/dev2-edge.conf"]) edit_cloudflare() edit_nginx_conf(spec) out = run(["/usr/local/sbin/nginx-edge-listen"], capture=True).stdout @@ -355,9 +359,12 @@ def new_sites(spec): def restore_live(tgz): """Undo a failed re-apply on a live edge: the Caddyfile, cert sources and stream map from the backup.""" - keep = {"etc/caddy/Caddyfile", "etc/caddy/edge-cert-sources", "etc/nginx/stream-enabled/dev2-edge.conf"} + keep = {"etc/caddy/Caddyfile", "etc/caddy/edge-cert-sources", "etc/nginx/stream-enabled/dev2-edge.conf", C0MPUTE_HTTP} with tarfile.open(tgz) as tf: members = [m for m in tf.getmembers() if m.name in keep] + # Not in the backup means this run added it: take it away again. + if C0MPUTE_HTTP not in {m.name for m in members} and os.path.exists("/" + C0MPUTE_HTTP): + os.remove("/" + C0MPUTE_HTTP) tf.extractall("/", members=members, **({"filter": "fully_trusted"} if hasattr(tarfile, "data_filter") else {})) run("nginx -t -q", capture=True) run("systemctl reload nginx") @@ -440,6 +447,9 @@ def rollback(tgz=None): def route(bundle): + for f in C0MPUTE_FILES[:1]: # the stream map includes the real-TLD map + if os.path.exists(f"{bundle}/root/{f}"): + put(f"{bundle}/root/{f}", "/" + f) put(f"{bundle}/root/etc/nginx/stream-enabled/dev2-edge.conf", STREAM_CONF) run("nginx -t -q", capture=True) run("systemctl reload nginx") diff --git a/dev2/edge/edge.json b/dev2/edge/edge.json index 5010e44..23fefae 100644 --- a/dev2/edge/edge.json +++ b/dev2/edge/edge.json @@ -1,6 +1,8 @@ { "//": "dev2 edge: which TLS names the nginx stream proxy hands to Caddy, and what Caddy does with them. Rendered by dev2/dev2-edge. Every upstream is the one nginx used before the move (2026-10-19). Certificates are NOT issued by Caddy: caddy-edge-certs copies the files the existing renewals (certbot, pit-proxy-cert, moshpit-renew) already keep current, and reloads Caddy when they change.", "ports": { "nginx": 8444, "caddy": 8453, "caddy_http": 8454, "caddy_admin": 2019 }, + "c0mpute_edge": { "tls": 8456, "http": 8457, + "//": "moshpit-proxy's c0mpute edge (systemd moshpit-c0mpute-edge, EDGE_PROXY_PROTOCOL=1, EDGE_FALLBACK=127.0.0.1:8444): every Moshpit-shaped name not listed here goes to it; it serves the c0mpute sites (edge.c0mpute.com is MOSHPIT_C0MPUTE_EDGE on the registry) and splices the rest back to nginx. iana-tlds.txt is what counts as not Moshpit." }, "caddy_version": "2.11.7", "stream_timeout": "24h", "nginx": { "worker_connections": 4096, "worker_rlimit_nofile": 16384 }, @@ -69,7 +71,6 @@ { "hosts": ["offtherecord.podcast", "otr.podcast"], "proxy": 8814, "max_body": "1MiB", "moshpit": true, "//": "Off The Record (moshcoder/offtherecord): pages, podcast feed, mp3 with ranges; the app 301s otr.podcast to offtherecord.podcast.pit.world" }, { "hosts": ["search.peptides"], "proxy": 8802, "max_body": "1MiB", "moshpit": true }, { "hosts": ["seo.rank"], "proxy": 8790, "max_body": "64KiB", "moshpit": true }, - { "hosts": ["alt.2600"], "root": "/var/www/alt.2600", "moshpit": true, "access_log": true }, { "hosts": ["auto.hacker"], "proxy": 8793, "max_body": "1MiB", "moshpit": true }, { "hosts": ["chovy.hacker"], "root": "/var/www/chovy.hacker", "moshpit": true, "access_log": true }, { "hosts": ["profullstack.agent"], "root": "/var/www/profullstack.agent", "moshpit": true, "access_log": true } diff --git a/dev2/edge/iana-tlds.txt b/dev2/edge/iana-tlds.txt new file mode 100644 index 0000000..775ffd3 --- /dev/null +++ b/dev2/edge/iana-tlds.txt @@ -0,0 +1,1437 @@ +# Version 2026110900, Last Updated Mon Nov 9 07:07:01 2026 UTC +AAA +AARP +ABB +ABBOTT +ABBVIE +ABC +ABLE +ABOGADO +ABUDHABI +AC +ACADEMY +ACCENTURE +ACCOUNTANT +ACCOUNTANTS +ACO +ACTOR +AD +ADS +ADULT +AE +AEG +AERO +AETNA +AF +AFL +AFRICA +AG +AGAKHAN +AGENCY +AI +AIG +AIRBUS +AIRFORCE +AIRTEL +AKDN +AL +ALIBABA +ALIPAY +ALLFINANZ +ALLSTATE +ALLY +ALSACE +ALSTOM +AM +AMAZON +AMERICANEXPRESS +AMERICANFAMILY +AMEX +AMFAM +AMICA +AMSTERDAM +ANALYTICS +ANDROID +ANQUAN +ANZ +AO +AOL +APARTMENTS +APP +APPLE +AQ +AQUARELLE +AR +ARAB +ARAMCO +ARCHI +ARMY +ARPA +ART +ARTE +AS +ASDA +ASIA +ASSOCIATES +AT +ATHLETA +ATTORNEY +AU +AUCTION +AUDI +AUDIBLE +AUDIO +AUSPOST +AUTHOR +AUTO +AUTOS +AW +AWS +AX +AXA +AZ +AZURE +BA +BABY +BAIDU +BANAMEX +BAND +BANK +BAR +BARCELONA +BARCLAYCARD +BARCLAYS +BAREFOOT +BARGAINS +BASEBALL +BASKETBALL +BAUHAUS +BAYERN +BB +BBC +BBT +BBVA +BCG +BCN +BD +BE +BEATS +BEAUTY +BEER +BERLIN +BEST +BESTBUY +BET +BF +BG +BH +BHARTI +BI +BIBLE +BID +BIKE +BING +BINGO +BIO +BIZ +BJ +BLACK +BLACKFRIDAY +BLOCKBUSTER +BLOG +BLOOMBERG +BLUE +BM +BMS +BMW +BN +BNPPARIBAS +BO +BOATS +BOEHRINGER +BOFA +BOM +BOND +BOO +BOOK +BOOKING +BOSCH +BOSTIK +BOSTON +BOT +BOUTIQUE +BOX +BR +BRADESCO +BRIDGESTONE +BROADWAY +BROKER +BROTHER +BRUSSELS +BS +BT +BUILD +BUILDERS +BUSINESS +BUY +BUZZ +BV +BW +BY +BZ +BZH +CA +CAB +CAFE +CAL +CALL +CALVINKLEIN +CAM +CAMERA +CAMP +CANON +CAPETOWN +CAPITAL +CAPITALONE +CAR +CARAVAN +CARDS +CARE +CAREER +CAREERS +CARS +CASA +CASE +CASH +CASINO +CAT +CATERING +CATHOLIC +CBA +CBN +CBRE +CC +CD +CENTER +CEO +CERN +CF +CFA +CFD +CG +CH +CHANEL +CHANNEL +CHARITY +CHASE +CHAT +CHEAP +CHINTAI +CHRISTMAS +CHROME +CHURCH +CI +CIPRIANI +CIRCLE +CISCO +CITADEL +CITI +CITIC +CITY +CK +CL +CLAIMS +CLEANING +CLICK +CLINIC +CLINIQUE +CLOTHING +CLOUD +CLUB +CLUBMED +CM +CN +CO +COACH +CODES +COFFEE +COLLEGE +COLOGNE +COM +COMMBANK +COMMUNITY +COMPANY +COMPARE +COMPUTER +COMSEC +CONDOS +CONSTRUCTION +CONSULTING +CONTACT +CONTRACTORS +COOKING +COOL +COOP +CORSICA +COUNTRY +COUPON +COUPONS +COURSES +CPA +CR +CREDIT +CREDITCARD +CREDITUNION +CRICKET +CROWN +CRS +CRUISE +CRUISES +CU +CUISINELLA +CV +CW +CX +CY +CYMRU +CYOU +CZ +DAD +DANCE +DATA +DATE +DATING +DATSUN +DAY +DCLK +DDS +DE +DEAL +DEALER +DEALS +DEGREE +DELIVERY +DELL +DELOITTE +DELTA +DEMOCRAT +DENTAL +DENTIST +DESI +DESIGN +DEV +DHL +DIAMONDS +DIET +DIGITAL +DIRECT +DIRECTORY +DISCOUNT +DISCOVER +DISH +DIY +DJ +DK +DM +DNP +DO +DOCS +DOCTOR +DOG +DOMAINS +DOT +DOWNLOAD +DRIVE +DTV +DUBAI +DUPONT +DURBAN +DVAG +DVR +DZ +EARTH +EAT +EC +ECO +EDEKA +EDU +EDUCATION +EE +EG +EMAIL +EMERCK +ENERGY +ENGINEER +ENGINEERING +ENTERPRISES +EPSON +EQUIPMENT +ER +ERICSSON +ERNI +ES +ESQ +ESTATE +ET +EU +EUROVISION +EUS +EVENTS +EXCHANGE +EXPERT +EXPOSED +EXPRESS +EXTRASPACE +FAGE +FAIL +FAIRWINDS +FAITH +FAMILY +FAN +FANS +FARM +FARMERS +FASHION +FAST +FEDEX +FEEDBACK +FERRARI +FERRERO +FI +FIDELITY +FIDO +FILM +FINAL +FINANCE +FINANCIAL +FIRE +FIRESTONE +FIRMDALE +FISH +FISHING +FIT +FITNESS +FJ +FK +FLICKR +FLIGHTS +FLIR +FLORIST +FLOWERS +FLY +FM +FO +FOO +FOOD +FOOTBALL +FORD +FOREX +FORSALE +FORUM +FOUNDATION +FOX +FR +FREE +FRESENIUS +FRL +FROGANS +FRONTIER +FTR +FUJITSU +FUN +FUND +FURNITURE +FUTBOL +FYI +GA +GAL +GALLERY +GALLO +GALLUP +GAME +GAMES +GAP +GARDEN +GAY +GB +GBIZ +GD +GDN +GE +GEA +GENT +GENTING +GEORGE +GF +GG +GGEE +GH +GI +GIFT +GIFTS +GIVES +GIVING +GL +GLASS +GLE +GLOBAL +GLOBO +GM +GMAIL +GMBH +GMO +GMX +GN +GODADDY +GOLD +GOLDPOINT +GOLF +GOODYEAR +GOOG +GOOGLE +GOP +GOT +GOV +GP +GQ +GR +GRAINGER +GRAPHICS +GRATIS +GREEN +GRIPE +GROCERY +GROUP +GS +GT +GU +GUCCI +GUGE +GUIDE +GUITARS +GURU +GW +GY +HAIR +HAMBURG +HANGOUT +HAUS +HBO +HDFC +HDFCBANK +HEALTH +HEALTHCARE +HELP +HERE +HERMES +HIPHOP +HISAMITSU +HITACHI +HIV +HK +HKT +HM +HN +HOCKEY +HOLDINGS +HOLIDAY +HOMEDEPOT +HOMEGOODS +HOMES +HOMESENSE +HONDA +HORSE +HOSPITAL +HOST +HOSTING +HOT +HOTELS +HOTMAIL +HOUSE +HOW +HR +HSBC +HT +HU +HUGHES +HYATT +HYUNDAI +IBM +ICBC +ICE +ICU +ID +IE +IEEE +IFM +IKANO +IL +IM +IMAMAT +IMDB +IMMO +IMMOBILIEN +IN +INC +INDUSTRIES +INFINITI +INFO +ING +INK +INSTITUTE +INSURANCE +INSURE +INT +INTERNATIONAL +INTUIT +INVESTMENTS +IO +IPIRANGA +IQ +IR +IRISH +IS +ISMAILI +IST +ISTANBUL +IT +ITAU +ITV +JAGUAR +JAVA +JCB +JE +JEEP +JETZT +JEWELRY +JIO +JLL +JM +JMP +JNJ +JO +JOBS +JOBURG +JOT +JOY +JP +JPMORGAN +JPRS +JUEGOS +KAUFEN +KDDI +KE +KERRYHOTELS +KERRYPROPERTIES +KFH +KG +KH +KI +KIA +KIDS +KIM +KINDLE +KITCHEN +KIWI +KM +KN +KOELN +KOMATSU +KOSHER +KP +KPMG +KPN +KR +KRD +KRED +KUOKGROUP +KW +KY +KYOTO +KZ +LA +LACAIXA +LAMBORGHINI +LAMER +LAND +LANDROVER +LANXESS +LASALLE +LAT +LATINO +LATROBE +LAW +LAWYER +LB +LC +LDS +LEASE +LECLERC +LEFRAK +LEGAL +LEGO +LEXUS +LGBT +LI +LIDL +LIFE +LIFEINSURANCE +LIFESTYLE +LIGHTING +LIKE +LILLY +LIMITED +LIMO +LINCOLN +LINK +LIVE +LIVING +LK +LLC +LLP +LOAN +LOANS +LOCKER +LOCUS +LOL +LONDON +LOTTE +LOTTO +LOVE +LPL +LPLFINANCIAL +LR +LS +LT +LTD +LTDA +LU +LUNDBECK +LUXE +LUXURY +LV +LY +MA +MADRID +MAIF +MAISON +MAKEUP +MAN +MANAGEMENT +MANGO +MAP +MARKET +MARKETING +MARKETS +MARRIOTT +MARSHALLS +MATTEL +MBA +MC +MCKINSEY +MD +ME +MED +MEDIA +MEET +MELBOURNE +MEME +MEMORIAL +MEN +MENU +MERCK +MERCKMSD +MG +MH +MIAMI +MICROSOFT +MIL +MINI +MINT +MIT +MITSUBISHI +MK +ML +MLB +MLS +MM +MMA +MN +MO +MOBI +MOBILE +MODA +MOE +MOI +MOM +MONASH +MONEY +MONSTER +MORMON +MORTGAGE +MOSCOW +MOTO +MOTORCYCLES +MOV +MOVIE +MP +MQ +MR +MS +MSD +MT +MTN +MTR +MU +MUSEUM +MUSIC +MV +MW +MX +MY +MZ +NA +NAB +NAGOYA +NAME +NAVY +NBA +NC +NE +NEC +NET +NETBANK +NETFLIX +NETWORK +NEUSTAR +NEW +NEWS +NEXT +NEXTDIRECT +NEXUS +NF +NFL +NG +NGO +NHK +NI +NICO +NIKE +NIKON +NINJA +NISSAN +NISSAY +NL +NO +NOKIA +NORTON +NOW +NOWRUZ +NOWTV +NP +NR +NRA +NRW +NTT +NU +NYC +NZ +OBI +OBSERVER +OFFICE +OKINAWA +OLAYAN +OLAYANGROUP +OLLO +OM +OMEGA +ONE +ONG +ONL +ONLINE +OOO +OPEN +ORACLE +ORANGE +ORG +ORGANIC +ORIGINS +OSAKA +OTSUKA +OTT +OVH +PA +PAGE +PANASONIC +PARIS +PARS +PARTNERS +PARTS +PARTY +PAY +PCCW +PE +PET +PF +PFIZER +PG +PH +PHARMACY +PHD +PHILIPS +PHONE +PHOTO +PHOTOGRAPHY +PHOTOS +PHYSIO +PICS +PICTET +PICTURES +PID +PIN +PING +PINK +PIONEER +PIZZA +PK +PL +PLACE +PLAY +PLAYSTATION +PLUMBING +PLUS +PM +PN +PNC +POHL +POKER +POLITIE +PORN +POST +PR +PRAXI +PRESS +PRIME +PRO +PROD +PRODUCTIONS +PROF +PROGRESSIVE +PROMO +PROPERTIES +PROPERTY +PROTECTION +PRU +PRUDENTIAL +PS +PT +PUB +PW +PWC +PY +QA +QPON +QUEBEC +QUEST +RACING +RADIO +RE +READ +REALESTATE +REALTOR +REALTY +RECIPES +RED +REDUMBRELLA +REHAB +REISE +REISEN +REIT +RELIANCE +REN +RENT +RENTALS +REPAIR +REPORT +REPUBLICAN +REST +RESTAURANT +REVIEW +REVIEWS +REXROTH +RICH +RICHARDLI +RICOH +RIL +RIO +RIP +RO +ROCKS +RODEO +ROGERS +ROOM +RS +RSVP +RU +RUGBY +RUHR +RUN +RW +RWE +RYUKYU +SA +SAARLAND +SAFE +SAFETY +SAKURA +SALE +SALON +SAMSCLUB +SAMSUNG +SANDVIK +SANDVIKCOROMANT +SANOFI +SAP +SARL +SAS +SAVE +SAXO +SB +SBI +SBS +SC +SCB +SCHAEFFLER +SCHMIDT +SCHOLARSHIPS +SCHOOL +SCHULE +SCHWARZ +SCIENCE +SCOT +SD +SE +SEARCH +SEAT +SECURE +SECURITY +SEEK +SELECT +SENER +SERVICES +SEVEN +SEW +SEX +SEXY +SFR +SG +SH +SHANGRILA +SHARP +SHELL +SHIA +SHIKSHA +SHOES +SHOP +SHOPPING +SHOUJI +SHOW +SI +SILK +SINA +SINGLES +SITE +SJ +SK +SKI +SKIN +SKY +SKYPE +SL +SLING +SM +SMART +SMILE +SN +SNCF +SO +SOCCER +SOCIAL +SOFTBANK +SOFTWARE +SOHU +SOLAR +SOLUTIONS +SONG +SONY +SOY +SPA +SPACE +SPORT +SPOT +SR +SRL +SS +ST +STADA +STAPLES +STAR +STATEBANK +STATEFARM +STC +STCGROUP +STOCKHOLM +STORAGE +STORE +STREAM +STUDIO +STUDY +STYLE +SU +SUCKS +SUPPLIES +SUPPLY +SUPPORT +SURF +SURGERY +SUZUKI +SV +SWATCH +SWISS +SX +SY +SYDNEY +SYSTEMS +SZ +TAB +TAIPEI +TALK +TAOBAO +TARGET +TATAMOTORS +TATAR +TATTOO +TAX +TAXI +TC +TCI +TD +TDK +TEAM +TECH +TECHNOLOGY +TEL +TEMASEK +TENNIS +TEVA +TF +TG +TH +THD +THEATER +THEATRE +TIAA +TICKETS +TIENDA +TIPS +TIRES +TIROL +TJ +TJMAXX +TJX +TK +TKMAXX +TL +TM +TMALL +TN +TO +TODAY +TOKYO +TOOLS +TOP +TORAY +TOSHIBA +TOTAL +TOURS +TOWN +TOYOTA +TOYS +TR +TRADE +TRADING +TRAINING +TRAVEL +TRAVELERS +TRAVELERSINSURANCE +TRUST +TRV +TT +TUBE +TUI +TUNES +TUSHU +TV +TVS +TW +TZ +UA +UBANK +UBS +UG +UK +UNICOM +UNIVERSITY +UNO +UOL +UPS +US +UY +UZ +VA +VACATIONS +VANA +VANGUARD +VC +VE +VEGAS +VENTURES +VERISIGN +VERSICHERUNG +VET +VG +VI +VIAJES +VIDEO +VIG +VIKING +VILLAS +VIN +VIP +VIRGIN +VISA +VISION +VIVA +VIVO +VLAANDEREN +VN +VODKA +VOLVO +VOTE +VOTING +VOTO +VOYAGE +VU +WALES +WALMART +WALTER +WANG +WANGGOU +WATCH +WATCHES +WEATHER +WEATHERCHANNEL +WEB +WEBCAM +WEBER +WEBSITE +WED +WEDDING +WEIBO +WEIR +WF +WHOSWHO +WIEN +WIKI +WILLIAMHILL +WIN +WINDOWS +WINE +WINNERS +WME +WOODSIDE +WORK +WORKS +WORLD +WOW +WS +WTC +WTF +XBOX +XEROX +XIHUAN +XIN +XN--11B4C3D +XN--1CK2E1B +XN--1QQW23A +XN--2SCRJ9C +XN--30RR7Y +XN--3BST00M +XN--3DS443G +XN--3E0B707E +XN--3HCRJ9C +XN--3PXU8K +XN--42C2D9A +XN--45BR5CYL +XN--45BRJ9C +XN--45Q11C +XN--4DBRK0CE +XN--4GBRIM +XN--54B7FTA0CC +XN--55QW42G +XN--55QX5D +XN--5SU34J936BGSG +XN--5TZM5G +XN--6FRZ82G +XN--6QQ986B3XL +XN--80ADXHKS +XN--80AO21A +XN--80AQECDR1A +XN--80ASEHDB +XN--80ASWG +XN--8Y0A063A +XN--90A3AC +XN--90AE +XN--90AIS +XN--9DBQ2A +XN--9ET52U +XN--9KRT00A +XN--B4W605FERD +XN--BCK1B9A5DRE4C +XN--C1AVG +XN--C2BR7G +XN--CCK2B3B +XN--CCKWCXETD +XN--CG4BKI +XN--CLCHC0EA0B2G2A9GCD +XN--CZR694B +XN--CZRS0T +XN--CZRU2D +XN--D1ACJ3B +XN--D1ALF +XN--E1A4C +XN--ECKVDTC9D +XN--EFVY88H +XN--FCT429K +XN--FHBEI +XN--FIQ228C5HS +XN--FIQ64B +XN--FIQS8S +XN--FIQZ9S +XN--FJQ720A +XN--FLW351E +XN--FPCRJ9C3D +XN--FZC2C9E2C +XN--FZYS8D69UVGM +XN--G2XX48C +XN--GCKR3F0F +XN--GECRJ9C +XN--GK3AT1E +XN--H2BREG3EVE +XN--H2BRJ9C +XN--H2BRJ9C8C +XN--HXT814E +XN--I1B6B1A6A2E +XN--IMR513N +XN--IO0A7I +XN--J1AEF +XN--J1AMH +XN--J6W193G +XN--JLQ480N2RG +XN--JVR189M +XN--KCRX77D1X4A +XN--KPRW13D +XN--KPRY57D +XN--KPUT3I +XN--L1ACC +XN--LGBBAT1AD8J +XN--MGB9AWBF +XN--MGBA3A3EJT +XN--MGBA3A4F16A +XN--MGBA7C0BBN0A +XN--MGBAAM7A8H +XN--MGBAB2BD +XN--MGBAH1A3HJKRD +XN--MGBAI9AZGQP6J +XN--MGBAYH7GPA +XN--MGBBH1A +XN--MGBBH1A71E +XN--MGBC0A9AZCG +XN--MGBCA7DZDO +XN--MGBCPQ6GPA1A +XN--MGBERP4A5D4AR +XN--MGBGU82A +XN--MGBI4ECEXP +XN--MGBPL2FH +XN--MGBT3DHD +XN--MGBTX2B +XN--MGBX4CD0AB +XN--MIX891F +XN--MK1BU44C +XN--MXTQ1M +XN--NGBC5AZD +XN--NGBE9E0A +XN--NGBRX +XN--NODE +XN--NQV7F +XN--NQV7FS00EMA +XN--NYQY26A +XN--O3CW4H +XN--OGBPF8FL +XN--OTU796D +XN--P1ACF +XN--P1AI +XN--PGBS0DH +XN--PSSY2U +XN--Q7CE6A +XN--Q9JYB4C +XN--QCKA1PMC +XN--QXA6A +XN--QXAM +XN--RHQV96G +XN--ROVU88B +XN--RVC1E0AM3E +XN--S9BRJ9C +XN--SES554G +XN--T60B56A +XN--TCKWE +XN--TIQ49XQYJ +XN--UNUP4Y +XN--VERMGENSBERATER-CTB +XN--VERMGENSBERATUNG-PWB +XN--VHQUV +XN--VUQ861B +XN--W4R85EL8FHU5DNRA +XN--W4RS40L +XN--WGBH1C +XN--WGBL6A +XN--XHQ521B +XN--XKC2AL3HYE2A +XN--XKC2DL3A5EE0H +XN--Y9A3AQ +XN--YFRO4I67O +XN--YGBI2AMMX +XN--ZFR164B +XXX +XYZ +YACHTS +YAHOO +YAMAXUN +YANDEX +YE +YODOBASHI +YOGA +YOKOHAMA +YOU +YOUTUBE +YT +YUN +ZA +ZAPPOS +ZARA +ZERO +ZIP +ZM +ZONE +ZUERICH +ZW diff --git a/test/dev2-edge.test.ts b/test/dev2-edge.test.ts index 21c6e1d..8b297be 100644 --- a/test/dev2-edge.test.ts +++ b/test/dev2-edge.test.ts @@ -139,6 +139,32 @@ describe('dev2-edge render', () => { expect(stream).toContain('hostnames;'); }); + it('sends Moshpit names nobody else routes to the c0mpute edge, real TLDs to nginx', () => { + const { d, stream } = render(); + const f = (p: string) => readFileSync(join(d, 'root', p), 'utf8'); + const edge = SPEC.c0mpute_edge; + // the catch-all is a regex, so exact names (Caddy's Moshpit names) still win + expect(stream).toContain(`"~^[a-z0-9-]+\\.[a-z0-9-]+$" 127.0.0.1:${edge.tls};`); + expect(stream).toContain('include /etc/nginx/dev2-edge/iana-tlds.stream.map;'); + expect(stream).toContain('map_hash_max_size 4096;'); + const tlds = f('etc/nginx/dev2-edge/iana-tlds.stream.map'); + // a wildcard beats a regex in a hostnames map: every real TLD stays on nginx + for (const t of ['com', 'sh', 'world', 'io']) expect(tlds).toContain(`\n.${t} 127.0.0.1:8444;`); + expect(tlds).not.toContain('.2600 '); + expect(tlds.split('\n').filter((l) => l.startsWith('.')).length).toBeGreaterThan(1000); + const http = f('etc/nginx/conf.d/c0mpute-edge-http.conf'); + expect(http).toContain(`proxy_pass http://127.0.0.1:${edge.http};`); + expect(http).toContain('error_page 421 = @parked;'); + expect(http).toContain('if ($moshpit_parked = 0) { return 301 https://$host$request_uri; }'); + expect(http).toContain('location ^~ /.well-known/acme-challenge/'); + }); + + it('--off drops the c0mpute route too', () => { + const { stream } = render(true); + expect(stream).not.toContain('iana-tlds'); + expect(stream).not.toContain(`127.0.0.1:${SPEC.c0mpute_edge.tls}`); + }); + it('--off routes every name to nginx (the fast way back)', () => { const { stream } = render(true); expect(stream).not.toContain(':8453');