Stop Paying for Cloud: Deploy a Highly Available Cluster on Your Own Hardware in Minutes

A 4-node highly available cluster with distributed storage, software-defined networking, and automatic failover. About 30 minutes to deploy. No Terraform. No Ansible playbooks. No 47-page architecture doc.

That’s Canonical’s MicroCloud: lightweight, repeatable cluster deployments built for edge computing and distributed workloads. Here’s the full walkthrough.

TL;DR: Install 4 snaps, run microcloud init on one node, microcloud join on the others, answer the storage/networking wizard, and you have a production-ready HA cluster. Full walkthrough below.

1. What Hardware Do You Actually Need?

Before touching the command line, you need the right hardware for your target environment. MicroCloud is flexible enough to support both lightweight test setups and production clusters.

Test/Development Environments

MicroCloud is lightweight enough that a test setup can start with a single-member deployment. You need as little as 8 GB of RAM per machine, and local storage is often sufficient.

Highly Available Production Environments

For production, redundancy is key. A highly available setup requires at least four physical nodes. Each machine should ideally feature 32 GB of RAM and 10 GB network cards to handle throughput.

Storage Allocation

Within each production node, you should allocate three separate NVMe disks: one for the operating system, one for local storage, and one for distributed storage (via Ceph).

Why four nodes? Separating disk types and maintaining a four-node count provides critical redundancy. If one node goes offline, the extra member ensures the cluster maintains a quorum, preventing a “split-brain” scenario where remaining nodes lose synchronization. Your applications stay reachable and highly available.

2. Install Everything in One Command

The foundation of your MicroCloud cluster is a clean, standardized operating system. Every server you intend to use must be provisioned with an Ubuntu Long-Term Support (LTS) release.

Once your servers are online, install the core services across every node. Canonical packages these components as containerized “snaps”:

sudo snap install microcloud lxd microceph microovn

Installing these services as snaps keeps your host operating system clean. All dependencies are bundled directly within the snap container, so you completely avoid package version conflicts.

3. The Cluster Handshake (Zero Manual SSL)

With the software installed, it’s time to establish the cluster using an automated handshake process.

Step 1: Initialize the Primary Node

Choose one machine to act as your initiator. SSH into this node and run:

sudo microcloud init

When the wizard asks if you want to set up more than one cluster member, select “yes”.

Step 2: Select Internal IPs

A table of available network interfaces will appear. Choose the specific IP address you want to use for MicroCloud’s internal cluster communication.

Step 3: Generate the Passphrase

The initiator terminal will generate a secure passphrase and enter a waiting state. Leave this session running.

Step 4: Join the Secondary Nodes

Open new SSH sessions into your remaining nodes and run:

sudo microcloud join

Select the corresponding internal IP address on each node, enter the passphrase generated by the primary node, and verify that the unique fingerprint matches.

This automates trust distribution between your nodes. No manual SSL certificate management. No private key distribution. Return to your initiator terminal, select all the secondary systems that reached out, and accept them into the cluster.

4. Storage: Local Speed + Distributed Safety

MicroCloud lets you pair the high-speed performance of local hardware with the resilience of a distributed cluster. The setup wizard guides you through configuring both.

Local Storage

When prompted to set up local storage pools, select exactly one designated disk from each machine.

Warning: Any disk you select for storage pools must be completely unpartitioned and free of any existing file systems. If you select a pre-formatted disk, the initialization will fail, and you’ll need to manually wipe the drives and restart the process.

Distributed Storage

Next, the wizard moves to distributed storage, handled by MicroCeph. You must select at least three unpartitioned disks across the cluster, as Ceph requires a minimum of three to properly replicate data for high availability. You will also be given options to wipe existing data, set up a CephFS distributed file system, or enable disk-level encryption.

This dual-storage strategy lets you run intensive edge workloads on fast local caching while ensuring your primary databases remain safely replicated across the distributed cluster.

5. Networking Without the Networking Pain

With compute and storage locked in, the wizard moves to network configuration, handled by MicroOVN. This software-defined network allows your virtual machines to communicate across the cluster.

External Uplink

The menu will display your physical network interfaces. Select one interface per machine to act as the external uplink. This uplink network must support both broadcast and multicast traffic for distributed networking to function correctly.

Gateways and IP Ranges

You will need to provide the IPv4 (and optionally IPv6) gateway for the uplink network using CIDR notation (e.g., 192.0.2.1/24). Then define a specific block of IPv4 addresses on your network reserved exclusively for your LXD instances.

Tip: MicroCloud uses mDNS (multicast DNS) to automatically discover the initiator node during setup. Some restrictive cloud environments block this traffic. If your secondary nodes can’t find the initiator, manually input the initiator’s static IP address to bypass the discovery phase and force the handshake.

6. Hit Enter, Get a Cloud

Once you answer the final prompts, MicroCloud takes over. It begins the automated bootstrap process, configuring and launching all requested services across every member of the cluster.

This turns what used to be a complex infrastructure deployment into a simple, repeatable process. Monitor the terminal output; when you see the final message stating “MicroCloud is ready,” your multi-node cluster is live, synchronized, and operational.

You can manage everything via the command line, or enable the Canonical LXD graphical user interface for centralized visual control over your instances, networks, and storage pools.

Your cluster is live. From here you can launch containers, spin up VMs, or start deploying workloads to the edge. All on your own hardware, under your own control, at a fraction of what you’d pay a cloud provider.

Anyone running MicroCloud in production? What’s your node count and what are you running on it?

I Got Tired of Cold Outreach. So I Made Claude Do It.

I Built an MCP That Turns Claude Into a Cold Outreach Machine — and It Actually Works

Submitted for the Notion MCP Challenge 2026

Let me be honest with you.

Cold outreach is broken.

Not because the idea is bad — cold emails work. People get hired, land clients, and build relationships through cold outreach every single day. It’s broken because of how long it actually takes to do it right.

Think about it. To send one good cold email, you have to:

  1. Find a company that’s actually a fit for your skills
  2. Go to their website and actually read it
  3. Figure out what they’re working on, what problems they might have
  4. Find a contact email somewhere on the site
  5. Write something that doesn’t sound like everyone else’s template
  6. Send it
  7. Log it somewhere so you don’t forget who you’ve reached out to

That’s 20–40 minutes. Per company.

If you do 10 companies — which is barely enough to move the needle — you’ve just burned a full workday on outreach alone.

So most people don’t do it. Or they send lazy, generic emails that get deleted in two seconds. Both outcomes are bad.

I got tired of it. So I built something.

Demo

What I Built: Cold Outreach MCP

Cold Outreach MCP is a custom MCP server that turns Claude into a fully automated cold email agent. You paste your CV once. Claude does everything else.

Here’s the exact flow:

You: "Here is my CV. Find 10 companies that match my background,
      research each one, and show me your recommendations."

Claude: [researches 10 companies]

      1. stripe.com → opportunity_pitch
         "Their checkout onboarding has friction — matches your UX background"

      2. linear.app → role_inquiry
         "Fast-growing team, strong eng culture, no obvious gap spotted"

      ... 8 more

You: "Looks good. Send as recommended."

Claude: [generates 10 tailored emails, sends them, logs everything to Notion]

That’s it. What used to take a full day now takes 3 minutes.

The Part That Actually Makes It Different

Most “automation” tools skip the part that matters most — the email itself.

They send templated garbage like:

“Hi [First Name], I came across [Company] and I was really impressed by your work in [Industry]. I think my background in [Skill] could add value to your team…”

Nobody replies to that. Everybody knows it’s a template. It goes straight to the bin.

Cold Outreach MCP does something different. Before generating the email, Claude actually reads the company’s website, identifies specific things about their product or team, and writes something that references what it found:

“Saw you’re building a design system at scale — I’ve done exactly this at [Company] and ran into the same versioning problems you’re probably hitting. Worth a quick chat?”

That’s an email someone opens. That’s an email someone replies to.

And the tone rules are hard-coded into the prompts:

  • Under 120 words
  • No buzzwords (“synergy”, “leverage”, “circle back” — all banned)
  • Short sentences. Casual but not sloppy.
  • One specific observation from their site
  • One clear ask at the end

It sounds like a person wrote it. Because an extremely good AI was told to write like a person.

Where Notion Fits In

Every outreach — sent, failed, or pending — gets logged to a Notion database automatically.

The schema looks like this:

Company Website Email Type Status Date Sent Notes
Stripe stripe.com [email protected] opportunity_pitch sent 2026-03-26 full email body
Linear linear.app [email protected] role_inquiry sent 2026-03-26 full email body

No manual logging. No “I think I emailed them last week?”. No spreadsheet.

And the Notion integration is set up like a proper database migration — you create an empty database on Notion, paste its ID in your config, run setup_notion_db once, and all the columns are provisioned automatically. It’s exactly how backend migrations work.

The 10 Tools Under the Hood

Tool What it does
setup_notion_db Migrates your Notion database — adds all required columns
parse_profile Extracts structured profile from your CV text
discover_companies Finds real companies that match your skills using Claude
find_company_email Scrapes a company site to find a contact email
research_company Analyzes a company — summary, pain points, recommended email type
generate_email Writes a human-sounding outreach email
send_email Sends via SMTP (Gmail, Outlook, anything)
log_to_notion Logs a record to your Notion tracker
retry_failed Re-attempts any failed sends automatically
bulk_outreach Full pipeline for up to 15 companies at once

It’s Human-in-the-Loop by Design

This is important. The tool doesn’t just fire off emails without asking you.

bulk_outreach runs in two phases:

Phase 1 — Claude researches all companies and returns its recommendations. You see everything before a single email is sent.

Phase 2 — You confirm (or override) each recommendation. Then and only then does Claude generate and send.

You’re always in control. The AI is doing the tedious work, not making the decisions for you.

There’s also a hard limit of 15 companies per run — enough to be productive, not enough to accidentally spam half the internet if something goes wrong.

Tech Stack

  • MCP SDK — @modelcontextprotocol/sdk (official Anthropic SDK)
  • AI — Claude via @anthropic-ai/sdk with adaptive thinking for research and email generation
  • Scraping — axios + cheerio for website analysis and email extraction
  • Email — nodemailer with lazy SMTP validation (server doesn’t crash if SMTP isn’t configured yet)
  • Notion — raw Notion REST API (fetch directly to https://api.notion.com/v1/...) for reliability
  • Language — TypeScript, Node.js 18+, ES modules

What the Setup Looks Like

git clone https://github.com/thecodedaniel/cold-outreach-mcp
cd cold-outreach-mcp
npm install && npm run build

Fill in your .env:

ANTHROPIC_API_KEY=sk-ant-...
NOTION_API_KEY=ntn_...
NOTION_DATABASE_ID=your_database_id
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
SMTP_PASS=your_app_password
[email protected]
SENDER_NAME=Your Name

Add to Claude Desktop config. Restart. Done.

The full setup takes about 10 minutes if you already have the API keys.

The One Thing I’m Most Proud Of

It’s not the scraping. It’s not the Notion integration. It’s not even the email generation.

It’s the fact that you don’t have to know which companies to target.

Every other tool in this space assumes you already know who you want to reach out to. You still have to do the research, compile the list, find the websites.

This one starts from your CV and figures out the rest. You describe what you do. Claude figures out who needs someone like you.

That’s the part that changes things.

What’s Next

  • Web search integration for real-time company discovery (Brave Search API)
  • Follow-up email scheduling (“no response in 7 days → send a nudge”)
  • Notion status tracking — mark a reply directly in Notion, trigger a follow-up draft
  • LinkedIn integration for finding decision-maker contacts

Links

Built for the Notion MCP Challenge 2026 by Daniel Ainoko (THECODEDANIEL)

If you’re a developer actively job hunting or trying to land clients — this is for you. The grind is real. Automate the boring parts.

When the App Goes Silent: The Hidden Cost of “No Orders”

Team GigEase | Guidewire DEVTrails 2026 — Scale Phase

When the App Goes Silent: The Hidden Cost of “No Orders”

Team [Your Team Name] | Guidewire DEVTrails 2026 — Scale Phase

Picture this.

It’s a late Sunday evening in Chennai. Arjun has been riding since noon. The dinner rush is just about to begin — the golden window where surge pricing kicks in and every delivery feels like progress.

He refreshes his app.

Nothing.

No orders.

He waits. Five minutes. Ten. Fifteen.

Still nothing.

He checks again. The map shows restaurants glowing red with demand. Riders nearby are moving. Orders are being fulfilled. But his screen stays silent.

By 9 PM, he realizes what has happened.

Earlier that afternoon, he had declined three long-distance orders in a row — the kind that take 40 minutes for ₹40. The algorithm noticed. Quietly. Without warning. And now, without explanation, it has pushed him down the priority list.

No notification. No reason. No appeal.

Just silence.

By the time he logs off, Arjun has earned ₹620 instead of the ₹2,000 he was counting on. The app never told him what went wrong. It just… stopped choosing him.

Tomorrow, he’ll log in again. Hoping the system “forgives” him.

This Is Not a Bug. It’s the System.

Across India’s gig platforms — Zomato, Swiggy, Blinkit, Zepto — millions of delivery partners operate inside opaque algorithmic systems.

These systems decide:

Who gets orders

Which orders they get

How far they travel

How much they earn

But here’s the reality:

Workers don’t understand the system that controls their income.

A rider can lose:

Priority due to a rejection streak

Earnings due to low acceptance rate

Visibility due to unknown ranking logic

And most importantly:

They are never told clearly why.

For a worker earning ₹500–₹800 per day, even one “bad algorithm day” is not just frustrating — it’s financially damaging.

The Question That Started Our Idea

We kept coming back to one uncomfortable question:

Why does Arjun have to guess how his livelihood works?

He is doing real-world labour — navigating traffic, weather, and time pressure.

But the system deciding his income is:

Invisible

Unpredictable

Unexplainable

What if that changed?

What if a rider could:

Understand why they are not getting orders

Predict how their actions affect earnings

Get real-time feedback on their performance

Make smarter decisions instead of blind guesses

That question became our project.

What We Are Building

We are building an AI-powered transparency layer for gig workers.

Think of it as a “co-pilot” for delivery partners.

Instead of replacing platforms, we sit alongside them and answer one simple question:

“What is happening to my earnings — and why?”

  1. Real-Time Earning Insights

Our system analyzes:

Acceptance rate

Order distance patterns

Time-of-day performance

Zone demand vs supply

It then tells the rider:

“You are receiving fewer orders because your acceptance rate dropped below 60% in the last hour.”

No guesswork. Just clarity.

  1. Smart Decision Guidance

Instead of blindly accepting or rejecting orders, riders get suggestions like:

“Accept next 2 orders to restore priority”

“Move 1.5 km towards high-demand zone”

“Avoid long-distance orders for next 30 mins”

This turns reactive work into strategic work.

  1. Earnings Prediction Engine

Using historical data + ML models, we estimate:

Expected hourly earnings

Best zones to operate

Peak earning windows

So instead of hoping for ₹2000/day, riders can plan for it.

  1. Fairness Alerts

If something unusual happens:

Sudden drop in order allocation

Abnormal earnings deviation

Platform-side inconsistencies

The system flags it.

Because sometimes, it’s not the rider.

What Building This Has Taught Us

  1. The biggest problem is not low income — it’s uncertainty

Workers can adapt to hard work.

They cannot adapt to randomness.

Predictability = power.

  1. Data without explanation is useless

Showing charts is not enough.

Riders need answers like:

“Your earnings dropped today because demand in your zone decreased by 35% after 8 PM.”

Not graphs. Not metrics. Clarity.

  1. Trust is everything

If a system gives wrong advice even twice, users stop trusting it.

So we focus heavily on:

Accuracy

Simplicity

Human-like explanations

  1. The system must never blame the worker unfairly

Sometimes the platform is the problem.

Sometimes demand is the problem.

Our job is to tell the truth, not just optimize behavior.

Why This Problem Matters

India’s gig economy is scaling fast.

But transparency is not.

Millions of workers are:

Managed by algorithms

Judged by hidden metrics

Paid based on unclear logic

Without visibility, they are not workers.

They are inputs in a system they cannot see.

What We Believe

We are not trying to replace gig platforms.

We are trying to rebalance information.

Because when a worker understands the system:

They earn better

They stress less

They make safer choices

And most importantly:

They regain control over their own work.

We Are Still Building

The models are evolving.

The predictions are improving.

The edge cases are endless.

But our guiding question remains the same:

Would this help Arjun make a better decision today?

If yes, we build.

If not, we rethink.

Closing Thought

A delivery partner’s job is already hard.

The system behind it shouldn’t make it harder.

If technology can control livelihoods,
it should also explain itself.

Team GigEase — Guidewire DEVTrails 2026
Making Gig Work Understandable, Predictable, and Fair

Your Site Is Up. Your Site Is Broken. Both Are True.

Every monitoring tool on the market will tell you when your site is down. None of them will tell you when your site returns HTTP 200 OK but serves a broken experience.

We built Sitewatch to close that gap. This post covers the detection engineering behind it — what we check, how we confirm failures, and why traditional uptime monitoring has a fundamental blind spot.

The Problem: 200 OK Is Not “OK”

A standard uptime monitor sends an HTTP request, gets a 200 status code, and marks your site as healthy. But a 200 response tells you almost nothing about whether your site actually works.

Here are real failure patterns that return 200 OK:

  • A Vercel deploy changes your bundle hash. main.a4f2c.js now 404s, but the HTML document still returns 200. Your app shell loads. Nothing renders.
  • Cloudflare serves app.js with Content-Type: text/html instead of application/javascript. Chrome silently blocks execution. The page loads — with zero interactivity.
  • A WordPress plugin misconfigures redirects. /checkout redirects to /checkout redirects to /checkout. The browser gives up. Your uptime tool never follows the chain.
  • After an AWS migration, your domain resolves to a decommissioned server. It serves stale content from six months ago. HTTP 200. Green dashboard.

Every one of these is invisible to a ping-based monitor. Every one of them is a real incident that affects users.

Our Detection Model: 11 Rules Across 3 Categories

We don’t just check “is the server responding.” We run 11 detection rules across three domains:

Asset Integrity

This is where most silent failures live.

ASSET_MISSING — We check whether critical JS, CSS, and image assets return valid responses. After a deploy, bundle filenames often change (hashed filenames like main.a4f2c.js). If the HTML references an asset that now 404s, 403s, or 5xxs, the page is broken even though the document loaded fine.

ASSET_MIME_MISMATCH — We verify that the Content-Type header matches what the browser expects. A JavaScript file served as text/html will be silently blocked by the browser’s MIME type checking. The page loads. The script never executes. No error in the server logs.

We use HEAD requests to check status codes and MIME types — no browser overhead, no JavaScript execution cost. If HEAD fails or returns ambiguous results, we fall back to GET.

Routing & Resolution

REDIRECT_LOOP — We follow redirect chains and detect circular patterns before ERR_TOO_MANY_REDIRECTS kills the request. We log the full chain with status codes and final destination.

HOST_DRIFT — We track the resolved IP and server headers over time. If your domain suddenly resolves to a different origin — common after DNS migrations, CDN changes, or failover misconfigurations — we flag it and compare the content fingerprint against the known baseline.

NON_HTML_PAGE — If a URL that should serve a web page returns JSON ({"error":"unauthorized"}), XML, or an empty body, we catch it. This happens more than you’d think with API gateways sitting in front of web apps.

Availability & Performance

UNAVAILABLE — The classic check. 5xx responses, timeouts, connection refused. We still do this — it’s just not the only thing we do.

Plus broken link checking (up to 50 links per page), API endpoint monitoring, and response structure validation.

Confirmation: The 2-of-3 Retry Model

False positives are the fastest way to lose trust in a monitoring tool. If your team gets woken up at 3am for a transient CDN glitch that resolved itself in 8 seconds, they stop trusting alerts. Then they miss the real ones.

We use a 2-of-3 retry confirmation model:

  1. First check detects an issue.
  2. We immediately re-check twice more.
  3. The issue must fail on at least 2 of 3 consecutive checks to become an incident.

A single transient failure — a momentary CDN hiccup, a network blip, a slow edge propagation — never triggers an alert. This eliminates the noise without adding dangerous delay. The entire confirmation cycle completes within the check interval.

For multi-region checks, this runs independently per region. A CDN edge failure in EU doesn’t need to reproduce in US to become an incident — but it does need to reproduce within its own region.

Fingerprinting: One Problem, One Incident

When an asset breaks, every check that hits that asset will detect the same failure. Without deduplication, a broken JS bundle could generate dozens of alerts over a few hours.

We generate a SHA-256 fingerprint for each detected issue — combining the failure type, affected URL, and relevant metadata. If an active incident already exists with the same fingerprint, we don’t create a new one. We also enforce a 30-minute per-incident cooldown on alert dispatches.

The result: 12 consecutive checks detecting the same broken asset → 1 alert, not 12.

Root Cause Classification

Detecting a failure is half the problem. The other half is telling you why it broke.

We classify every incident into one of 10 cause families across three domains:

Infrastructure: DNS resolution failure, origin server error, SSL/TLS certificate issue, network connectivity.

Application: Deployment artifact missing, application error, configuration drift.

Content Delivery: CDN cache misconfiguration, third-party dependency failure, redirect misconfiguration.

Classification uses evidence from the check data — HTTP headers, response content, redirect behavior, MIME types, IP resolution, and fingerprint diffs. We assign a confidence score up to 90%. A high-confidence diagnosis (70%+) means the evidence strongly matches a known failure pattern.

Stack-Aware Context

Knowing what broke and why is useful. Knowing how to fix it for your specific stack is what actually saves time.

We detect 23 tech stacks by analyzing HTTP response headers (X-Powered-By, Server, X-Vercel-Id), HTML meta tags, script patterns, and asset URL structures. Detection happens automatically with every check — no configuration required.

When an incident fires, the fix guidance is tailored to your stack. A “deployment artifact missing” incident on Vercel gets different remediation steps than the same failure on Netlify or a self-hosted Nginx setup.

Multi-Region: Catching Regional Divergence

CDN failures are often regional. Your site might work perfectly from US-East while EU users get stale cached assets from a failed purge.

Multi-region checks run the full detection suite from multiple geographic points. Each region runs its own independent 2-of-3 retry confirmation. We compare results across regions to distinguish between:

  • Global outage — all regions failing
  • Regional divergence — specific edges serving different content, stale caches, or geo-routing sending traffic to wrong origins

This catches CDN edge divergence, geo-routing misconfigurations, and regional failover failures — problems that are invisible if you only check from one location.

What We Don’t Do

We don’t run a headless browser. We don’t execute JavaScript. We don’t render the page and take screenshots.

This is a deliberate choice. Browser-based monitoring is slow, expensive, and fragile. It catches visual regressions — which matters — but it’s a different problem from “your assets are broken and your site is non-functional.”

Our checks are HTTP-based. They’re fast, cheap to run at high frequency, and they catch the structural failures that actually take sites down in production. Visual regression testing is complementary but separate.

The Architecture in Summary

Check cycle:
  1. Fetch document (GET)
  2. Verify status, content-type, body structure
  3. Extract and verify critical assets (HEAD requests)
  4. Follow redirect chains
  5. Compare fingerprints against baseline
  6. Run detection rules (11 rules)
  7. 2-of-3 retry on failures
  8. Classify root cause (10 families, up to 90% confidence)
  9. Match tech stack (23 stacks)
  10. Generate incident with evidence + fix guidance
  11. Deduplicate and dispatch alerts

All of this runs every 5–30 minutes depending on plan, from multiple regions, without requiring any code changes or agent installation on your infrastructure.

Try It

Sitewatch has a free tier — 1 site, 30-minute checks, no credit card. If you manage multiple sites and want to catch the failures your current monitoring misses, that’s what we built it for.

getsitewatch.com

If you have questions about the detection approach or want to dig into specific failure patterns, drop a comment — happy to go deeper on any of this.

Xperience Community: Content Repositories

If you have been building with Xperience by Kentico, you are probably familiar with the repetitive ceremony around fetching web page content: URL resolution, language detection, caching, null guards. It is the kind of code you write once per project and then paste — slightly modified — into the next one.

The Xperience Community: Content Repository package was built to centralize exactly that kind of logic. And with version 1.0.2, it gets a meaningful new addition: the WebPageRepository.

What’s New in v1.0.2

This release ships two things:

  • IWebPageRepository and WebPageRepository — a new repository for resolving web page URLs by GUID, with built-in language awareness and caching.
  • Kentico package upgrades — all Kentico dependencies bumped to 31.2.0.

The web page repository is small in surface area but fills a real gap. It gives you a single, safe place to resolve a WebPageUrl from a GUID, handles language fallbacks automatically, and caches results intelligently so you’re not hitting the database on every request.

Installation

Add the package via the .NET CLI:

dotnet add package XperienceCommunity.ContentRepository

Then register all repositories in your Program.cs:

services.AddXperienceContentRepositories();

That’s it. IWebPageRepository is now registered in DI and ready to use.

The WebPageRepository

The new repository exposes a single, focused method:

public interface IWebPageRepository
{
    Task<WebPageUrl?> GetUrlByGuid(Guid webPageGuid, string? languageName = null);
}

Under the hood, WebPageRepository wires together three Kentico services — IWebPageUrlRetriever, IPreferredLanguageRetriever, and IProgressiveCache — so you do not have to.

Here is what the implementation does for you:

  • GUID guard — returns null immediately if the GUID is empty, avoiding pointless lookups.
  • Language resolution — if no language is passed, it falls back to the current preferred language via IPreferredLanguageRetriever.
  • Progressive caching — caches the resolved URL for 60 minutes, scoped to the GUID and language. Cache is invalidated via the webpageitem|byguid|{guid} dependency, so stale URLs are never served after a content update.
  • Graceful error handling — if URL retrieval fails for any reason (page doesn’t exist, routing misconfiguration), it returns null and skips caching the failed result.

For the full implementation, check the repository on GitHub.

Usage

You can access it directly through DI or via the centralized ContentRepositories accessor:

// Via direct injection
public class MyService(IWebPageRepository webPageRepository)
{
    public async Task<string?> GetPageUrl(Guid pageGuid)
    {
        var url = await webPageRepository.GetUrlByGuid(pageGuid);
        return url?.RelativePath;
    }
}
// Via ContentRepositories accessor
public class MyOtherService(ContentRepositories repos)
{
    public async Task<string?> GetPageUrl(Guid pageGuid)
    {
        var repo = repos.GetWebPageRepository();
        var url = await repo.GetUrlByGuid(pageGuid);
        return url?.RelativePath;
    }
}

You can also pass a language explicitly when you need to resolve a URL for a specific locale rather than the current preferred language:

var url = await webPageRepository.GetUrlByGuid(pageGuid, languageName: "es");

Why This Matters

URL resolution from a GUID might sound trivial, but it is a frequent request in real Xperience projects — especially when building navigation menus, breadcrumbs, related content links, or any component that stores references to other pages by GUID rather than by full path.

Without something like this, you typically end up either writing the caching boilerplate yourself for each use case, or skipping caching altogether and accepting the performance cost. The WebPageRepository solves that cleanly in one place.

What’s Already in the Package

The WebPageRepository joins an already capable set of repositories. A quick summary of what the package covers:

  • IPageTypeRepository<T> — query web page content types by ID, GUID, path, taxonomy tag, or custom where conditions.
  • IContentTypeRepository<T> — retrieve reusable content items with pagination, smart folder support, and multi-type queries.
  • IMediaFileRepository — fetch media files by GUID or from asset related items, with caching included.
  • ICacheDependencyBuilder — a utility for assembling cache dependencies consistently across your project.
  • ContentRepositories — a centralized accessor that provides all repositories through a single injected service.

Conclusion

Version 1.0.2 of Xperience Community: Content Repository is a focused update — a new repository that handles one common task well, paired with a dependency upgrade to Kentico 31.2.0. If you are already using the package, updating is straightforward. If you have not tried it yet, this is a good moment to add it to your toolbox.

The NuGet package is available at nuget.org/packages/XperienceCommunity.ContentRepository, and the full source is on GitHub.

Follow me on social:

Cloud Egress Costs Explained: Why Your Architecture Is Paying a Tax You Never Modeled

Cloud egress costs explained — data transfer pricing, egress multipliers, and architecture patterns that generate hidden cloud bills

Cloud egress costs explained — data transfer pricing, egress multipliers, and architecture patterns that generate hidden cloud bills

You modeled compute. You modeled storage. You built cost estimates, ran capacity planning, and got sign-off on the architecture before a single resource was provisioned.

You did not model what it costs to move data.

Cloud egress is the tax that accumulates invisibly — not from a single expensive operation, but from thousands of small data movement events your architecture was never designed to account for. It shows up as a line item in the monthly bill that nobody owns, that nobody predicted, and that grows consistently as the system scales.

This guide covers what cloud egress costs actually are, where they come from, the architectural patterns that multiply them silently, and how to model them before the invoice arrives rather than after it does.

What Cloud Egress Actually Is

Egress is data leaving a cloud environment. Every time your system moves data — from a server to a user, from one region to another, from one availability zone to another — there is a potential cost event attached to it. Inbound data transfer (ingress) is almost always free. Outbound data transfer (egress) is almost always metered.

Three distinct egress categories — most architecture reviews only account for one:

Internet egress — data leaving the cloud provider entirely. This is the egress line item that appears in every cloud cost guide. It is also, for many architectures, not the largest egress cost.

Cross-region egress — data moving between two regions within the same cloud provider. For architectures with active multi-region deployments, this cost compounds quickly.

Cross-zone egress — the one most teams miss entirely until they see the bill. Availability zones within the same region are not free to communicate. AWS charges $0.01/GB in each direction for cross-AZ data transfer. In a microservice architecture spread across multiple AZs for high availability — as it should be — every inter-service call that crosses an AZ boundary is a billable event.

Provider Internet Egress (first 10TB) Cross-Region Cross-Zone Free Tier
AWS $0.09/GB $0.02/GB $0.01/GB each direction 100GB/month
GCP (Premium Tier) $0.08/GB $0.01–0.08/GB $0.01/GB 1GB/month
GCP (Standard Tier) $0.085/GB $0.01–0.08/GB $0.01/GB 1GB/month
Azure $0.087/GB $0.02/GB $0.01/GB 5GB/month

Rates vary by region, volume tier, and service. Check current provider pricing pages before budgeting.

Storage Is Cheap. Moving Data Out of It Isn’t.

Object storage is one of the cheapest resources in the cloud. S3, GCS, and Azure Blob Storage charge fractions of a cent per GB per month for standard storage.

The cost is not in storing the data. It is in every system that reads it.

Analytics queries that scan large datasets pull gigabytes from object storage to compute on every execution. An ML training pipeline that reads training data from S3 into a GPU instance generates egress from storage to compute on every epoch. A data pipeline that copies data between storage tiers generates egress at every stage rather than transforming in place.

Storage is cheap. Moving data out of it isn’t.

The architectural response: collocate compute with storage in the same region and AZ, query data in place with serverless analytics engines (BigQuery, Athena, Redshift Spectrum), and use caching layers to prevent repeated reads of the same data across pipeline stages.

Cloud object storage egress cost diagram showing analytics queries, ML training pipelines, and data pipeline fan-out generating hidden egress costs from cheap storage

Egress Multipliers

Most egress cost analyses focus on individual data transfer events. The real problem is architectural patterns that multiply egress — where a single user action, pipeline trigger, or retry event generates orders of magnitude more data movement than the operation itself warrants.

Fan-Out Architectures

A single inbound request triggers N downstream service calls, each of which pulls data from storage, calls an external API, or crosses a zone boundary. One user action becomes ten egress events. Ten concurrent users become a hundred. Fan-out architectures are correct designs for scalability — they become egress problems when the fan-out multiplier is never modeled against data transfer costs.

Retry Storms

A service encounters a transient failure and retries with the full request payload. At scale, retry storms generate egress volume that can exceed the original traffic by multiples — the same data transferred repeatedly without successful delivery. Retry logic without exponential backoff, jitter, or payload size awareness turns a brief service degradation into a sustained egress event.

Cross-Zone Microservice Chatter

Microservice architectures distributed across AZs for resilience generate inter-AZ traffic on every service-to-service call that crosses a zone boundary. A request chain that traverses five services across three AZs generates five potential cross-zone transfer events — each metered at $0.01/GB each direction. Zone-aware routing reduces this without sacrificing the availability architecture.

Data Duplication Pipelines

ETL and ELT pipelines that copy data between storage tiers — raw to processed, processed to curated — generate egress at every stage rather than transforming in place. A pipeline that copies 1TB through four stages transfers 4TB, not 1TB. The architectural alternative is transformation in place using serverless query engines.

Egress rarely comes from a single path. It comes from paths that multiply.

Cloud egress multiplier patterns diagram showing fan-out architectures, retry storms, cross-zone microservice chatter, and data duplication pipelines

Where the Hidden Costs Live by Provider

AWS charges $0.01/GB in each direction for cross-AZ traffic within the same region — easy to miss because it appears as a line item shared across dozens of services. For microservice architectures with high inter-service call volumes across AZs, this compounds into significant monthly spend.

GCP’s global VPC model eliminates many cross-zone cost traps that AWS architectures encounter. A single VPC spans all regions, and intra-region traffic between zones is cheaper than the AWS equivalent. The more significant GCP egress decision is Premium Tier versus Standard Tier — Premium Tier keeps traffic on Google’s private backbone, Standard Tier routes via the public internet.

Azure follows a similar cross-zone model to AWS, with inter-AZ transfer metered within a region. Azure’s ExpressRoute provides private connectivity with different egress economics for enterprise hybrid architectures with high on-premises-to-cloud data movement.

The provider comparison matters less than the architectural principle: wherever data moves across a billing boundary — zone, region, or provider — that movement has a cost, and that cost multiplies with request volume.

AI and Inference Egress: The New Problem

Inference pipelines have introduced an egress cost category that traditional architecture cost models were never designed to capture. An inference request that pulls retrieval context from object storage, queries a vector database in a different zone, calls an embedding model in a separate service, and returns a response has generated egress events at every step.

AI inference cost is the new egress. The principle established in cloud architecture for data movement — that cost emerges from behavior, not provisioning — applies directly to inference pipelines.

The architectural response is data gravity: run inference where the data lives. A GPU instance in the same AZ as the vector database it queries and the object storage it reads from eliminates the cross-zone egress events that accumulate invisibly in architectures where compute and data were placed independently.

How to Reduce Egress Costs

Egress cost reduction is an architecture exercise, not a FinOps exercise. The levers that actually move the number are design decisions.

1. Collocate compute and data. Place compute in the same region and AZ as the data it consumes. Zone-aware Kubernetes scheduling — topology spread constraints and affinity rules — reduces cross-zone chatter without changing the service architecture.

2. Query in place. Use serverless analytics engines — BigQuery, Athena, Redshift Spectrum — to run queries against data where it lives rather than pulling it to dedicated compute.

3. Cache aggressively. CDN caching eliminates internet egress for repeated requests. In-memory caching reduces cross-zone calls for frequently accessed data. Every cache hit is an egress event that did not happen.

4. Compress before transfer. High-ratio compression (zstd, Brotli) reduces egress volume by 60–80% for large dataset transfers. Binary serialization (Protocol Buffers, Avro) reduces inter-service payload size by 3–10x versus JSON.

5. Audit the multipliers. Before optimizing individual transfer rates, identify which architectural patterns are generating the highest egress volume. Fan-out patterns, retry storms, and cross-zone chatter are more valuable to fix than negotiating a lower per-GB rate.

Tool: Cloud Egress Calculator — model true data movement costs across AWS, Azure, and GCP. Whether you’re migrating to a new provider, setting up multi-cloud disaster recovery, or running cross-region analytics — this exposes the hidden tiered pricing models before the bill arrives.

Architect’s Verdict

Egress is not a billing problem. It is an architecture problem that surfaces as a billing problem after the system is in production and the design decisions that generated it are too expensive to reverse.

The teams that control egress costs are not the ones running tighter FinOps reviews. They are the ones who modeled data movement as a first-class architectural constraint at design time — who asked “what does this data transfer cost at 10x volume?” before the architecture was approved, not after the first invoice arrived.

The patterns that generate the largest egress bills are not misconfigurations. They are correct architectural decisions — high availability across AZs, fan-out for scalability, retry logic for resilience — made without egress as a design input.

Model it like compute. Model it like storage. It is the same tax, arriving from a direction you didn’t expect.

Additional Resources

From Rack2Cloud:

External:

Originally published at Rack2Cloud.com