#!/usr/bin/env python3 """MacLustr public website (multi-page). Stdlib only (Python 3.9+). Runs on m2u64, serves http://0.0.0.0:8004 -> ngrok www.maclustr.io.""" import json, os, html from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from urllib.parse import urlparse HERE = os.path.dirname(os.path.abspath(__file__)) PORT = 8004 CONTACT = "spbou4@protonmail.com" NODES = json.load(open(os.path.join(HERE, "nodes.json"))) TIER_ORDER = {"ULTRA": 0, "MAX": 1, "PRO": 2, "BASE": 3} TCOLOR = {"ULTRA": "#5B21B6", "MAX": "#7C3AED", "PRO": "#2563EB", "BASE": "#0891B2"} def esc(s): return html.escape(str(s)) def gb_to_tb(g): return f"{g/1024:.1f} TB" if g >= 1024 else f"{g} GB" def store_gb(v): v = (v or "").strip() if v.endswith("TB"): return int(float(v.replace("TB", "").strip())) * 1024 if v.endswith("GB"): return int(float(v.replace("GB", "").strip())) return 0 # ---- modern line icons (Lucide-style, stroke=currentColor) ---- _P = { "cpu":'', "server":'', "cloud":'', "zap":'', "lock":'', "command":'', "mail":'', "arrow":'', "layers":'', "db":'', "globe":'', "check":'', "gauge":'', "gpu":'', "chip":'', "hd":'', } def icon(name, size=24, cls=""): return (f'{_P.get(name,"")}') CSS = """ :root{--bg:#fafbfd;--card:#fff;--ink:#0e1016;--ink2:#3a3f4b;--mut:#737a89;--line:#edeff4; --acc:#7c3aed;--acc2:#2f6bff;--ring:rgba(124,58,237,.14); --sh:0 1px 2px rgba(16,24,40,.04),0 1px 3px rgba(16,24,40,.06); --sh2:0 12px 40px rgba(16,24,40,.10);--r:22px} *{box-sizing:border-box;margin:0;padding:0} html{-webkit-text-size-adjust:100%;scroll-behavior:smooth} body{font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text",Helvetica,Arial,sans-serif; background:var(--bg);color:var(--ink);line-height:1.6;-webkit-font-smoothing:antialiased;letter-spacing:-.01em} a{color:inherit;text-decoration:none} svg{display:block} .wrap{max-width:1080px;margin:0 auto;padding:0 20px} /* nav */ .nav{position:sticky;top:0;z-index:20;background:rgba(250,251,253,.72);backdrop-filter:saturate(180%) blur(16px);border-bottom:1px solid var(--line)} .nav .in{max-width:1080px;margin:0 auto;padding:13px 20px;display:flex;align-items:center;gap:12px} .nav .logo{width:32px;height:32px;border-radius:9px;box-shadow:var(--sh)} .nav .nm{font-weight:800;font-size:17px;letter-spacing:-.02em} .nav .links{margin-left:auto;display:flex;align-items:center;gap:6px} .nav .links a{padding:8px 13px;border-radius:11px;font-size:14px;font-weight:600;color:var(--mut);transition:.15s} .nav .links a:hover{color:var(--ink);background:#f1f2f7} .nav .links a.on{color:var(--ink);background:#eef0f6} .nav .cta{margin-left:6px;background:var(--ink);color:#fff!important;padding:9px 16px!important;border-radius:11px;font-weight:700} .nav .cta:hover{background:#000;opacity:1} @media(max-width:640px){.nav .links a:not(.cta){display:none}} /* generic */ .kick{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:700;letter-spacing:.3px;color:var(--acc); background:var(--ring);padding:6px 13px;border-radius:999px} .eyebrow{text-align:center} h1{font-size:clamp(40px,7.5vw,74px);font-weight:830;letter-spacing:-.035em;line-height:1.02} h2{font-size:clamp(28px,5vw,42px);font-weight:800;letter-spacing:-.03em;line-height:1.08} .grad{background:linear-gradient(105deg,var(--acc),var(--acc2));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent} .lead{font-size:clamp(16px,2.4vw,20px);color:var(--mut);max-width:660px;line-height:1.55} .section{padding:62px 0} .center{text-align:center}.mx{margin-left:auto;margin-right:auto} .btn{display:inline-flex;align-items:center;gap:9px;font-weight:750;font-size:15.5px;padding:14px 24px;border-radius:14px;transition:.15s} .btn.p{background:var(--ink);color:#fff;box-shadow:var(--sh2)} .btn.p:hover{transform:translateY(-1px)} .btn.g{background:var(--card);color:var(--ink);border:1px solid var(--line);box-shadow:var(--sh)} .btn.g:hover{background:#f6f7fb} .row-btn{display:flex;gap:12px;flex-wrap:wrap} .hero{padding:74px 0 24px;text-align:center} .hero .logo{width:84px;height:84px;border-radius:22px;box-shadow:var(--sh2);margin:0 auto 24px} .hero .lead{margin:20px auto 0} .hero .row-btn{justify-content:center;margin-top:32px} /* stats */ .stats{display:grid;grid-template-columns:repeat(5,1fr);gap:13px;margin-top:54px} @media(max-width:780px){.stats{grid-template-columns:repeat(2,1fr)}} .stat{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:22px 16px;text-align:center;box-shadow:var(--sh)} .stat .ic{color:var(--acc);margin:0 auto 10px;width:24px} .stat .n{font-size:clamp(24px,4.6vw,34px);font-weight:830;letter-spacing:-.03em;font-variant-numeric:tabular-nums} .stat .l{font-size:12px;font-weight:650;text-transform:uppercase;letter-spacing:.5px;color:var(--mut);margin-top:3px} /* feature cards */ .cards{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:36px} @media(max-width:820px){.cards{grid-template-columns:1fr}} .fcard{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:26px;box-shadow:var(--sh);transition:.18s} .fcard:hover{box-shadow:var(--sh2);transform:translateY(-2px)} .fcard .ic{width:50px;height:50px;border-radius:15px;display:flex;align-items:center;justify-content:center;color:#fff; background:linear-gradient(135deg,var(--acc),var(--acc2));box-shadow:0 6px 16px var(--ring);margin-bottom:16px} .fcard h3{font-size:20px;font-weight:780;letter-spacing:-.02em} .fcard p{color:var(--mut);font-size:14.8px;margin-top:8px} .fcard ul{list-style:none;margin-top:14px;display:grid;gap:8px} .fcard li{display:flex;gap:9px;font-size:14px;color:var(--ink2)} .fcard li svg{color:var(--acc);flex:0 0 auto;margin-top:3px} /* nodes */ .tier{display:flex;align-items:center;gap:12px;margin:34px 0 14px} .tier .pill{display:inline-flex;align-items:center;color:#fff;font-weight:750;font-size:13px;padding:6px 15px;border-radius:10px} .tier .d{color:var(--mut);font-size:13.5px} .nodes{display:grid;grid-template-columns:repeat(auto-fill,minmax(252px,1fr));gap:14px} .node{background:var(--card);border:1px solid var(--line);border-radius:18px;padding:18px;box-shadow:var(--sh);position:relative;overflow:hidden} .node:before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--tc)} .node .h{display:flex;align-items:baseline;gap:8px} .node .nm{font-size:22px;font-weight:820;letter-spacing:-.02em} .node .md{margin-left:auto;font-size:12px;color:var(--mut);font-weight:600} .node .ch{font-size:12.5px;color:var(--ink2);font-weight:700;margin-top:1px} .node .sp{display:grid;grid-template-columns:1fr 1fr;gap:6px 16px;margin-top:14px;font-size:13.5px} .node .sp>div{display:flex;justify-content:space-between;border-bottom:1px solid var(--line);padding-bottom:5px} .node .sp span{color:var(--mut)}.node .sp b{font-weight:700;font-variant-numeric:tabular-nums} /* split / about */ .split{display:grid;grid-template-columns:1.1fr .9fr;gap:40px;align-items:center} @media(max-width:820px){.split{grid-template-columns:1fr;gap:24px}} .mini{display:grid;grid-template-columns:1fr 1fr;gap:12px} .mini .stat{padding:18px 14px;text-align:left}.mini .stat .ic{margin:0 0 8px} /* steps */ .steps{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:34px;counter-reset:s} @media(max-width:820px){.steps{grid-template-columns:1fr}} .step{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:24px;box-shadow:var(--sh)} .step .no{width:34px;height:34px;border-radius:11px;background:var(--ring);color:var(--acc);font-weight:800;display:flex;align-items:center;justify-content:center;margin-bottom:13px} .step h3{font-size:18px;font-weight:760}.step p{color:var(--mut);font-size:14.5px;margin-top:6px} /* contact band */ .band{background:linear-gradient(140deg,#15102a,#1f1640 55%,#10213f);color:#fff;border-radius:30px;padding:clamp(36px,6vw,64px);text-align:center;box-shadow:var(--sh2)} .band h2{color:#fff}.band p{color:#cdc8e6;max-width:620px;margin:14px auto 0;font-size:17px} .band .mail{display:inline-flex;align-items:center;gap:11px;margin-top:28px;background:#fff;color:#15102a;font-weight:800; font-size:clamp(15px,3.6vw,21px);padding:16px 28px;border-radius:15px;word-break:break-all} .chips{display:flex;gap:9px;justify-content:center;flex-wrap:wrap;margin-top:22px} .chips span{background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.16);padding:7px 15px;border-radius:999px;font-size:13.5px;font-weight:600} /* pricing plans */ .plans{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:36px} @media(max-width:900px){.plans{grid-template-columns:repeat(2,1fr)}} @media(max-width:520px){.plans{grid-template-columns:1fr}} .plan{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:24px;box-shadow:var(--sh);display:flex;flex-direction:column} .plan.hot{border-color:transparent;background:linear-gradient(160deg,#1a1230,#231a40);color:#fff;box-shadow:var(--sh2)} .plan .tg{display:inline-flex;align-self:flex-start;color:#fff;font-weight:750;font-size:12px;padding:5px 12px;border-radius:8px;letter-spacing:.4px} .plan h3{font-size:21px;font-weight:800;margin-top:14px;letter-spacing:-.02em} .plan .from{font-size:12.5px;color:var(--mut);margin-top:14px;font-weight:600} .plan.hot .from{color:#bdb6da} .plan .price{font-size:40px;font-weight:840;letter-spacing:-.03em;line-height:1} .plan .price small{font-size:15px;font-weight:700;color:var(--mut)} .plan.hot .price small{color:#bdb6da} .plan p{color:var(--mut);font-size:13.8px;margin-top:12px} .plan.hot p{color:#cdc8e6} .plan ul{list-style:none;margin-top:14px;display:grid;gap:7px;flex:1} .plan li{display:flex;gap:8px;font-size:13.3px;color:var(--ink2)} .plan.hot li{color:#e7e2f5} .plan li svg{color:var(--acc);flex:0 0 auto;margin-top:2px} .plan.hot li svg{color:#b794ff} .plan a.cta2{margin-top:18px;text-align:center;background:var(--ink);color:#fff;font-weight:750;padding:12px;border-radius:12px;font-size:14.5px} .plan.hot a.cta2{background:#fff;color:#1a1230} /* pricing table */ .ptable{margin-top:18px;border:1px solid var(--line);border-radius:18px;overflow:hidden;box-shadow:var(--sh);background:var(--card)} .pscroll{overflow-x:auto} table.pg{border-collapse:collapse;width:100%;min-width:620px;font-size:14px} table.pg th,table.pg td{text-align:right;padding:13px 14px;border-bottom:1px solid var(--line);white-space:nowrap} table.pg th:first-child,table.pg td:first-child,table.pg th:nth-child(2),table.pg td:nth-child(3){text-align:left} table.pg thead th{font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--mut);font-weight:750;background:#fafbfd} table.pg tbody tr:last-child td{border-bottom:0} table.pg tbody tr:hover{background:#fafbfd} table.pg .node-nm{font-weight:800;letter-spacing:-.01em} table.pg .tg{display:inline-block;color:#fff;font-size:11px;font-weight:750;padding:3px 9px;border-radius:7px} table.pg .spec{color:var(--mut);font-variant-numeric:tabular-nums} table.pg .ml{font-weight:800;font-variant-numeric:tabular-nums} table.pg .aws{color:var(--mut);text-decoration:line-through;font-variant-numeric:tabular-nums} table.pg .num{font-variant-numeric:tabular-nums} .note{color:var(--mut);font-size:12.5px;margin-top:14px;line-height:1.6} /* whole-cluster banner */ .clusterbox{background:linear-gradient(140deg,#15102a,#1f1640 55%,#10213f);color:#fff;border-radius:28px;padding:clamp(28px,5vw,52px);box-shadow:var(--sh2);margin-top:34px} .clusterbox .kick{background:rgba(255,255,255,.14);color:#fff} .clusterbox h2{color:#fff;margin-top:14px} .clusterbox .sub2{color:#cdc8e6;margin-top:10px;font-size:16.5px;max-width:640px} .cl-prices{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:26px} @media(max-width:680px){.cl-prices{grid-template-columns:repeat(2,1fr)}} .cl-prices>div{background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.15);border-radius:16px;padding:18px 16px} .cl-prices .hl{background:#fff;color:#15102a;border-color:#fff} .cl-prices .l{font-size:11.5px;font-weight:750;text-transform:uppercase;letter-spacing:.5px;opacity:.82} .cl-prices .n{font-size:clamp(22px,3.6vw,32px);font-weight:840;letter-spacing:-.03em;margin-top:5px;font-variant-numeric:tabular-nums} .cl-prices .p{font-size:12px;opacity:.7;margin-top:2px} .cl-incl{display:flex;flex-wrap:wrap;gap:8px;margin-top:24px} .cl-incl span{background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.16);padding:7px 14px;border-radius:999px;font-size:13px;font-weight:600} .clusterbox .btn{margin-top:26px;background:#fff;color:#15102a} .clusterbox .fine{color:#b3aace;font-size:12.5px;margin-top:16px;line-height:1.6} /* footer */ footer{border-top:1px solid var(--line);margin-top:30px} footer .in{max-width:1080px;margin:0 auto;padding:30px 20px;display:flex;gap:14px;align-items:center;flex-wrap:wrap;color:var(--mut);font-size:13.5px} footer .nm{display:flex;align-items:center;gap:9px;font-weight:750;color:var(--ink)} footer .nm img{width:24px;height:24px;border-radius:7px} footer .lk{margin-left:auto;display:flex;gap:18px} footer .lk a:hover{color:var(--ink)} """ def nav(active): def lk(href, label, key): return f'{label}' return f"""""" def footer(): return f"""""" def shell(title, active, body, desc=""): return f""" {esc(title)} {nav(active)}{body}{footer()}""" def totals(): return dict( n=len(NODES), cpu=sum(n["ncpu"] for n in NODES), gpu=sum(n["gpu"] for n in NODES), ne=sum(n["ne"] for n in NODES), ram=sum(n["mem"] for n in NODES), store=sum(store_gb(n["internal"]) + store_gb(n["external"]) for n in NODES), ) def stat(ic, n, l): return f'
{icon(ic)}
{n}
{l}
' def stats_block(): t = totals() return (f'
' f'{stat("server",t["n"],"Nodes")}' f'{stat("cpu",t["cpu"],"CPU cores")}' f'{stat("chip",t["ram"],"GB unified RAM")}' f'{stat("gpu",t["gpu"],"GPU cores")}' f'{stat("hd",gb_to_tb(t["store"]),"SSD storage")}' f'
') def node_card(n): storage = f'{n["internal"]} SSD' + (f' + {n["external"]} ext' if n["external"] else "") return (f'
' f'
{esc(n["alias"])}{esc(n["model"])}
' f'
{esc(n["chip"])}
' f'
' f'
CPU{n["ncpu"]}c
' f'
GPU{n["gpu"]}c
' f'
RAM{n["mem"]} GB
' f'
Neural{n["ne"]}c
' f'
Storage{esc(storage)}
' f'
') def nodes_grouped(): order = sorted(NODES, key=lambda n: (TIER_ORDER.get(n["tier"], 9), -n["ncpu"], -n["mem"])) tiers = {} for n in order: tiers.setdefault(n["tier"], []).append(n) desc = {"ULTRA": "Mac Studio · M-series Ultra — heaviest compute & training", "MAX": "Mac Studio / MacBook Pro · M-series Max — high-throughput workloads", "PRO": "Mac mini · M-series Pro — balanced services & build agents", "BASE": "Mac mini / MacBook Air · M-series — lightweight always-on services"} out = "" for t, lst in tiers.items(): out += (f'
{esc(t)}' f'{len(lst)} node{"s" if len(lst)>1 else ""} · {esc(desc.get(t,""))}
' f'
{"".join(node_card(n) for n in lst)}
') return out # ---------- pages ---------- def page_home(): t = totals() body = f"""
{icon('command',16)} Self-hosted · Apple Silicon

The self-hosted
Apple Silicon cluster

A private cluster of {t['n']} Apple Silicon Macs — Mac Studio, MacBook Pro, Mac mini and MacBook Air — networked for distributed compute, hosting and private cloud.

{stats_block()}
Why MacLustr

Real hardware, not a rented VM

We pool genuine Apple Silicon — {t['cpu']} CPU cores, {t['ram']} GB unified memory, {t['gpu']} GPU cores and {t['ne']} Neural Engine cores — into one cluster you fully control.

{icon('zap')}

Distributed compute

Spread heavy jobs across {t['n']} machines — ML training & inference, simulation, batch processing and rendering.

{icon('cloud')}

Private cloud

Your own always-on infrastructure: APIs, databases, model servers and storage on dedicated hardware.

{icon('command')}

Native macOS

True Apple Silicon for macOS/iOS builds, CI agents and anything that must run on real Macs.

{contact_band()}
""" return shell("MacLustr — Self-Hosted Apple Silicon Compute Cluster", "home", body, f"MacLustr is a self-hosted cluster of {t['n']} Apple Silicon Macs for compute, hosting and private cloud.") def page_nodes(): t = totals() body = f"""
{icon('layers',16)} The fleet

Every node, fully specced

{t['n']} dedicated Apple Silicon Macs, grouped by tier. Pick the one that matches your workload.

{stats_block()}
{nodes_grouped()}
{contact_band()}
""" return shell("Nodes — MacLustr", "nodes", body, "Full specifications of every MacLustr cluster node.") def page_services(): body = f"""
{icon('server',16)} Services

What you can run on MacLustr

Three ways to put our Apple Silicon to work — rent it by the job, host a service, or get a private slice of cloud.

{icon('gauge')}

Compute

Rent cores and GPU / Neural Engine time for demanding jobs.

  • {icon('check',16)} ML training & inference
  • {icon('check',16)} Simulation & data processing
  • {icon('check',16)} Batch jobs & rendering
{icon('globe')}

Hosting

Run a service on a dedicated node with a real public endpoint.

  • {icon('check',16)} Websites & APIs
  • {icon('check',16)} Bots & background workers
  • {icon('check',16)} Public HTTPS endpoint
{icon('lock')}

Private cloud

An isolated, always-on slice of the cluster that's yours.

  • {icon('check',16)} Storage & databases
  • {icon('check',16)} Model & app servers
  • {icon('check',16)} Dedicated, isolated resources
How it works

From request to running

1

Tell us your workload

Email a short description — what you want to run, rough resources and how long.

2

We match a node

We pick the right tier — Ultra, Max, Pro or Base — and set up access.

3

You go live

Get credentials / an endpoint and start running. Monitor each node's live page anytime.

{contact_band()}
""" return shell("Services — MacLustr", "services", body, "Compute, hosting and private cloud on the MacLustr Apple Silicon cluster.") def page_about(): t = totals() # model breakdown counts = {} for n in NODES: counts[n["model"]] = counts.get(n["model"], 0) + 1 chips = " · ".join(f"{v}× {k}" for k, v in sorted(counts.items(), key=lambda x: -x[1])) body = f"""
{icon('cpu',16)} About

A cluster built from real Macs

MacLustr is a self-hosted cluster of {t['n']} Apple Silicon Macs running native macOS. Instead of renting generic cloud VMs, we pool genuine Mac hardware — fast unified memory, powerful GPUs and Neural Engines, and energy-efficient Apple Silicon — into one cluster you can run heavy workloads on.

The fleet spans {esc(chips)} — from top-tier Ultra Studios for training down to efficient minis and Airs for always-on services.

{stat("cpu",t["cpu"],"CPU cores")} {stat("chip",t["ram"],"GB RAM")} {stat("gpu",t["gpu"],"GPU cores")} {stat("command",t["ne"],"Neural cores")} {stat("server",t["n"],"Nodes")} {stat("hd",gb_to_tb(t["store"]),"SSD")}
Principles

Why self-hosted

{icon('lock')}

Yours, end to end

Dedicated hardware you control — no noisy neighbours, no surprise migrations.

{icon('zap')}

Efficient & fast

Apple Silicon delivers huge unified memory and performance per watt.

{icon('gauge')}

Transparent

Every node has a live status page — see real CPU, memory and disk anytime.

{contact_band()}
""" return shell("About — MacLustr", "about", body, "About the MacLustr self-hosted Apple Silicon cluster.") def page_contact(): body = f"""
{icon('mail',16)} Contact

Let's find the right node for you

Need compute, hosting or private cloud on one of our nodes? Send a short note about your workload and we'll get back to you.

{contact_band()}

What to include

{icon('gauge')}

Your workload

What you want to run — compute job, a service to host, or a private cloud space.

{icon('chip')}

Rough resources

Cores, memory, GPU, storage — even a ballpark helps us match a tier.

{icon('db')}

Duration

One-off job or always-on? Let us know the timeframe.

""" return shell("Contact — MacLustr", "contact", body, f"Contact MacLustr at {CONTACT} for compute, hosting and cloud.") # ---- pricing (USD). MacLustr rate ~= 10% below a comparable AWS EC2 Mac Dedicated Host. ---- # rate = MacLustr $/h ; AWS est. $/h = rate / 0.9 ; day = rate*24 ; month = rate*730 RATES = { "m3u96a": 8.44, "m3u96b": 8.44, "m2u64": 7.47, "m4m64a": 7.47, "m4m64b": 7.47, "m4bp48": 6.72, "m4m36": 5.41, "m4bp36": 5.41, "m2m32": 1.40, "m2m32b": 1.40, "m2m32c": 1.40, "m1m32": 1.35, "m4mc": 0.77, "m2m16": 0.99, "m4ma": 1.11, "m4mb": 0.96, "m3ba24": 0.59, "m3ba16": 0.51, "m2m8a": 0.43, "m2m8b": 0.43, } PLANS = [ ("ULTRA", "#5B21B6", "AI & heavy compute", 7.50, True, "M-series Ultra & M4 Max with 64–96 GB unified memory. Built for model training, large-context inference and the heaviest jobs.", ["64–96 GB unified memory", "Up to 60 GPU + 32 Neural cores", "Dedicated, isolated host", "24h minimum"]), ("MAX", "#7C3AED", "High-throughput power", 5.50, False, "M4 Max nodes with 36–48 GB. Strong GPU and compute for demanding production workloads.", ["36–48 GB unified memory", "40 GPU cores · 16 CPU cores", "Latest-gen Apple Silicon", "Dedicated host"]), ("STUDIO", "#2563EB", "Dedicated mid-tier", 1.35, False, "M2 / M1 Max Studios with ~32 GB. Reliable dedicated power at an accessible price.", ["30–32 GB unified memory", "24–30 GPU cores", "Always-on dedicated node", "Great price/perf"]), ("WORKER", "#0891B2", "CI · hosting · light AI", 0.43, False, "Mac mini & MacBook Air (M-series Pro/Base). Perfect for CI/CD, web hosting, agents and light inference.", ["8–24 GB unified memory", "Mac mini / MacBook Air", "Web & API hosting, CI runners", "Pay only for what you run"]), ] def fmt(v): return f"${v:,.2f}" def fmt0(v): return f"${v:,.0f}" def plan_card(p): tier, color, tag, frm, hot, desc, feats = p feats_html = "".join(f"
  • {icon('check',16)} {f}
  • " for f in feats) return (f'
    ' f'{tier}' f'

    {tag}

    ' f'
    from
    ' f'
    {fmt(frm)}/hour
    ' f'

    {desc}

      {feats_html}
    ' f'Request access
    ') def pricing_rows(): rows = "" order = sorted(NODES, key=lambda n: -RATES.get(n["slug"], 0)) for n in order: h = RATES.get(n["slug"], 0) aws = h / 0.9 day = h * 24 month = h * 730 spec = f'{n["ncpu"]}C / {n["gpu"]}G / {n["mem"]}GB' rows += (f'{esc(n["alias"])}' f'{esc(n["tier"])}' f'{esc(spec)}' f'{fmt(aws)}' f'{fmt(h)}' f'{fmt(day)}' f'{fmt0(month)}/mo') return rows def whole_cluster(): compute_h = sum(RATES.values()) storage_mo = 35000 * 0.05 + 45000 * 0.02 # 35 TB SSD + 45 TB HDD external total_h = compute_h + storage_mo / 730 day = total_h * 24 month = total_h * 730 year = total_h * 8760 t = totals() def cell(label, val, per, hl=False): return (f'
    {label}
    ' f'
    {val}
    {per}
    ') return f"""
    {icon('layers',16)} Whole infrastructure

    Rent the entire cluster

    Every node and all external storage, exclusively yours — a turn-key private Apple Silicon cloud.

    {cell("Hourly", fmt(total_h), "per hour")} {cell("Daily", fmt0(day), "24 hours")} {cell("Monthly", fmt0(month), "730 hours", hl=True)} {cell("Yearly", fmt0(year), "8,760 hours")}
    {t['n']} nodes{t['cpu']} CPU cores{t['ram']} GB RAM{t['gpu']} GPU cores{t['ne']} Neural cores35 TB SSD + 45 TB HDD external
    Reserve the full cluster {icon('arrow',18)}

    Includes every node (with their internal SSDs) plus the full 80 TB external storage pool — 35 TB SSD and 45 TB HDD. Annual and long-term commitments qualify for a custom discount.

    """ def page_pricing(): body = f"""
    {icon('gauge',16)} Pricing

    Dedicated Apple Silicon, ~10% below AWS

    Transparent per-node pricing, benchmarked against AWS EC2 Mac Dedicated Hosts (24-hour minimum). Rent by the hour, day, month or year.

    {whole_cluster()}
    {icon('server',16)} By the node

    Or pick a plan

    {"".join(plan_card(p) for p in PLANS)}
    {icon('layers',16)} Full price list

    Every node, per hour

    Hourly rate, plus 24-hour and 730-hour (monthly) totals. AWS column shows a comparable EC2 Mac Dedicated Host estimate.

    {pricing_rows()}
    NodeTierSpecs (CPU/GPU/RAM)AWS est.MacLustr /h/day (24h)/month (730h)

    Prices in USD. Specs shown as CPU cores / GPU cores / unified memory. MacLustr /h is our rate; AWS est. is a comparable AWS EC2 Mac Dedicated Host (on-demand, 24h minimum) — MacLustr runs about 10% below. Monthly assumes 730 hours of continuous use; short jobs are billed hourly. Custom and long-term plans available on request.

    {icon('hd',16)} Storage add-ons

    Need more space?

    Attach external storage to any node — fast SSD for hot data, high-capacity HDD for archives and backups. Pay per gigabyte, per month.

    {icon('hd')}

    External SSD

    Fast SSD storage for active datasets, databases and model weights.

    $0.05 / GB · month
    • {icon('check',16)} ≈ $50 per TB · month
    • {icon('check',16)} Up to 35 TB available
    • {icon('check',16)} High throughput, low latency
    {icon('db')}

    External HDD

    High-capacity spinning disk for archives, backups and cold storage.

    $0.02 / GB · month
    • {icon('check',16)} ≈ $20 per TB · month
    • {icon('check',16)} Up to 45 TB available
    • {icon('check',16)} Ideal for backups & archives

    Storage add-ons are billed per GB-month and attach to any rented node. Total external pools available: 35 TB SSD and 45 TB HDD. Larger or dedicated volumes available on request.

    {contact_band()}
    """ return shell("Pricing — MacLustr", "pricing", body, "MacLustr pricing: dedicated Apple Silicon nodes ~10% below comparable AWS EC2 Mac Dedicated Hosts.") def contact_band(): return f"""

    Need compute, hosting or cloud?

    If you need any kind of computation, hosting or private cloud on one of our nodes, write to us — describe your workload and we'll find the right node.

    {icon('mail',20)}{CONTACT}
    Compute jobsML training / inferenceWeb & API hostingPrivate cloudmacOS CI
    """ ROUTES = {"": page_home, "nodes": page_nodes, "services": page_services, "pricing": page_pricing, "about": page_about, "contact": page_contact} LOGO_PATH = os.path.join(HERE, "logo.svg") LOGO = open(LOGO_PATH).read() if os.path.exists(LOGO_PATH) else "" class H(BaseHTTPRequestHandler): def log_message(self, *a): pass def _send(self, code, body, ctype="text/html; charset=utf-8"): b = body.encode() if isinstance(body, str) else body self.send_response(code) self.send_header("Content-Type", ctype) self.send_header("Content-Length", str(len(b))) self.send_header("Cache-Control", "no-store") self.end_headers() try: self.wfile.write(b) except (BrokenPipeError, ConnectionResetError): pass def do_GET(self): path = urlparse(self.path).path.strip("/") if path in ("health", "healthz"): return self._send(200, "ok", "text/plain") if path == "logo.svg": return self._send(200, LOGO, "image/svg+xml") if path in ROUTES: return self._send(200, ROUTES[path]()) nf = '

    Page not found

    Sorry, that page does not exist.

    ' return self._send(404, shell("Not found — MacLustr", "", nf)) if __name__ == "__main__": srv = ThreadingHTTPServer(("0.0.0.0", PORT), H) print(f"MacLustr landing on :{PORT} ({len(NODES)} nodes)") srv.serve_forever()