Category: Uncategorized

  • Deploy a Simple k3s Cluster on an Ubuntu Server (with HTTPS)

    You don’t need a managed cloud or a three-node control plane to run Kubernetes in production. A single Ubuntu VPS and k3s — a lightweight, certified Kubernetes distribution — will happily serve several apps with automatic HTTPS. This is the exact setup we use for our own sites, boiled down to the steps that matter.

    Key Takeaways

    • k3s installs a full Kubernetes cluster on one Ubuntu box with a single command, bundling the Traefik ingress controller and local-path storage.
    • cert-manager plus Let’s Encrypt gives you free, auto-renewing HTTPS — as long as port 80 stays reachable.
    • The whole bootstrap is idempotent: safe to re-run, easy to script.

    What are we building?

    One Ubuntu server running k3s, with three things layered on top: Traefik as the ingress controller (bundled with k3s), cert-manager for TLS certificates, and a ufw firewall exposing only SSH, HTTP, and HTTPS. Everything installs from the official upstream scripts and manifests — no third-party tooling.

    You’ll need a fresh Ubuntu server you can SSH into as root, and (for the HTTPS part) a domain you control.

    Step 1: Base packages and Docker

    First, the essentials. rsync for copying files to the server, ca-certificates for TLS trust, and ufw for the firewall:

    export DEBIAN_FRONTEND=noninteractive
    apt-get update -q
    apt-get install -yq rsync ca-certificates ufw

    Docker is optional for running k3s. If you plan to build container images on the server itself, though, install Docker CE from the official convenience script:

    if ! command -v docker >/dev/null; then
      curl -fsSL https://get.docker.com | sh
    fi

    Note the if guard: every step in this guide is written to be idempotent, so you can re-run the whole thing safely.

    Step 2: Install k3s

    This is the step that feels too easy. One command installs the k3s server, sets it up as a systemd service, and starts a fully working Kubernetes cluster:

    curl -sfL https://get.k3s.io | sh -

    k3s bundles two components you’d otherwise install yourself: the Traefik ingress controller (listening on ports 80/443) and the local-path storage provisioner (PersistentVolumes backed by the node’s disk, under /var/lib/rancher/k3s/storage/).

    The node object can take a few seconds to appear after first start, so wait for it before continuing:

    for i in $(seq 1 30); do kubectl get nodes >/dev/null 2>&1 && break; sleep 2; done
    kubectl wait --for=condition=Ready node --all --timeout=120s

    When kubectl get nodes shows Ready, you have a working cluster. As root, kubectl works out of the box — the installer writes the cluster credentials to /etc/rancher/k3s/k3s.yaml and wires the CLI up to them.

    Step 3: Install cert-manager

    cert-manager automates the entire TLS lifecycle: it requests certificates from Let’s Encrypt, solves the validation challenges, and renews certificates before they expire. Install it from the official release manifest and wait for the rollout:

    CERT_MANAGER_VERSION="v1.18.2"
    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml
    kubectl -n cert-manager rollout status deploy/cert-manager --timeout=180s
    kubectl -n cert-manager rollout status deploy/cert-manager-webhook --timeout=180s

    Then give it a ClusterIssuer — the resource that tells cert-manager how to talk to Let’s Encrypt. HTTP-01 is the simplest challenge type: Let’s Encrypt makes an HTTP request to your domain on port 80, and cert-manager answers it through Traefik.

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-prod
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email: you@example.com
        privateKeySecretRef:
          name: letsencrypt-prod-account-key
        solvers:
          - http01:
              ingress:
                class: traefik

    Tip from experience: create a second issuer pointing at Let’s Encrypt’s staging endpoint (https://acme-staging-v02.api.letsencrypt.org/directory) and use it for your first attempt on a new domain. Staging avoids the production rate limit of 5 failed validations per hour — a limit that’s easy to hit while you’re still debugging DNS.

    Step 4: Firewall

    Lock the box down to exactly three ports:

    ufw allow 22/tcp
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw --force enable

    One rule to tattoo somewhere visible: port 80 stays open forever. It’s not just for redirects — Let’s Encrypt’s HTTP-01 renewal challenges arrive on port 80. Close it and your certificates will silently fail to renew a few weeks later.

    Step 5: DNS and your first HTTPS app

    Point an A record at your server’s IP and wait until dig +short yourdomain.com returns it. If your DNS provider is Cloudflare, keep the record set to DNS only (grey cloud, proxy off) — with the proxy on, Let’s Encrypt’s validation request never reaches your server and issuance breaks.

    Now any Ingress you deploy gets HTTPS with two additions — the issuer annotation and a tls: block:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-app
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
    spec:
      ingressClassName: traefik
      rules:
        - host: app.yourdomain.com
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: my-app
                    port:
                      number: 80
      tls:
        - hosts: [app.yourdomain.com]
          secretName: my-app-tls

    Watch the certificate get issued — it’s usually Ready within a minute:

    kubectl get certificate -w

    If a certificate stays un-Ready, kubectl describe certificaterequest tells you why, and kubectl describe challenge is where HTTP-01 failures actually surface. The first thing to check: does port 80 actually reach Traefik from the internet?

    Frequently Asked Questions

    Is single-node k3s really production-ready?

    For small workloads, yes — we run our company site, a WordPress blog, an API, and a cluster dashboard on one node. You give up high availability, so a node failure means downtime. Know that trade-off, take backups, and single-node k3s is a pragmatic, low-cost choice.

    Why k3s instead of full Kubernetes (kubeadm)?

    k3s is a certified Kubernetes distribution packaged as a single small binary. You get the same API with far less setup: ingress and storage come bundled, and upgrades are a re-run of the install script. For a single server there’s little reason to take on kubeadm’s extra moving parts.

    How do apps survive pod restarts?

    Use PersistentVolumeClaims with the bundled local-path storage class. Data lands on the node’s disk under /var/lib/rancher/k3s/storage/ and survives pod restarts and re-applies. Remember it’s node-local: back it up separately, because it lives and dies with the server.

    Wrapping up

    That’s the whole stack: five steps from a bare Ubuntu box to a Kubernetes cluster serving HTTPS traffic. The same pattern scales from a hobby project to real client workloads — this blog is being served by exactly this setup right now.

    Want to see what we run on ours? Read about our cluster dashboard, or what MashupSoft does with infrastructure like this for clients.

  • Introducing MashupSoft: AI-Powered Software, Shipped in Weeks

    Welcome to the MashupSoft engineering blog. We build AI-powered software that helps businesses automate workflows, engage customers, and scale efficiently. This is where we’ll write about how we do it. First things first: who are we, and why should you care?

    Key Takeaways

    • MashupSoft delivers AI-powered web and mobile applications, workflow automation, and digital transformation under one roof.
    • Automated workflows we’ve shipped cut manual processing time by 68% (MashupSoft client results).
    • First working releases ship in 2–6 weeks from kickoff — weeks, not quarters.

    Who is MashupSoft?

    MashupSoft is a software team covering the full journey from idea to production: web, mobile, and backend together. We apply AI where it saves real hours, not where it looks good in a pitch deck. Our promise is simple: practical solutions that turn ideas into measurable business results.

    We’re not a body shop and we’re not a research lab. We sit in the useful middle: one team that can take a bottleneck in your business, prototype a fix, and ship it to production fast.

    What we build

    Four things, and we build them well:

    • AI-powered web applications — modern web platforms with intelligent search, assistants, and decision support built in, not bolted on.
    • Mobile applications — native-quality iOS and Android apps from a single codebase, designed for daily use and built to scale.
    • Workflow automation — we map your repetitive processes and replace them with AI agents and integrations that run around the clock.
    • Digital transformation — legacy processes to cloud-native systems, on a pragmatic roadmap delivered increment by increment.

    Curious about the details? Our About page has the full picture.

    How we work

    From bottleneck to shipped in four steps: Discover → Prototype → Build → Scale. We start by understanding what actually slows your team down. Then we prove the idea with a working prototype, build it properly, and stay on to scale it.

    The numbers from work we’ve shipped tell the story better than we can:

    • −68% manual processing time on automated workflows
    • 2–6 weeks from kickoff to first working release
    • 24/7 AI agents working while your team sleeps

    One operations lead at a logistics client put it this way: “The workflow that used to eat two days of every week now runs itself. We just review the exceptions.”

    What will you find on this blog?

    Engineering notes, mostly. We run our own infrastructure and practice what we ship — this site itself runs on a Kubernetes cluster we manage, and we’ve already written about wiring WordPress up to MCP and our cluster dashboard setup. Expect hands-on posts about AI agents, automation, and cloud-native operations — the same tools and techniques we use for client work.

    Frequently Asked Questions

    What does MashupSoft do?

    We build AI-powered web and mobile applications, automate business workflows with AI agents, and modernize legacy systems into cloud-native platforms. One team covers design through production, shipping in weeks rather than quarters.

    How fast can you deliver?

    Our track record is 2–6 weeks from kickoff to a first working release. We ship a working prototype early, then build on it steadily rather than disappearing for a quarter.

    How do I get started?

    Tell us what slows your team down at contact@mashupsoft.com. We reply within one business day with an honest take on whether AI can fix it. If it can’t, we’ll say so.


    Have a workflow that deserves automating? Talk to us — or visit mashupsoft.com to see what we’re building.

  • Headlamp on k3s: A Web Dashboard for Our Kubernetes Cluster

    Behind the scenes, everything on mashupsoft.com — this blog included — runs on a single-node k3s cluster. Up to now, checking on it meant SSHing in and running kubectl by hand. Not anymore: we just stood up a proper web dashboard.

    Meet Headlamp

    Headlamp is an open-source, general-purpose UI for Kubernetes clusters. We deployed it in-cluster and put it behind its own subdomain, dash.mashupsoft.com, so we can see pods, deployments, and cluster health at a glance instead of grepping terminal output.

    How it’s secured

    Access is gated by a Kubernetes ServiceAccount token with cluster-admin rights, scoped to Headlamp alone — the same mechanism the Kubernetes API itself trusts, rather than a bolted-on password layer. We initially fronted it with HTTP Basic Auth at the ingress too, but pulled that back out: Headlamp sends its own Authorization: Bearer header on API calls, and that clashes with Basic credentials on the same header, so the two auth layers couldn’t stack. The ServiceAccount token now does the job on its own, and the token itself never leaves the cluster.

    TLS is handled the same way as the rest of the domains here — cert-manager and Let’s Encrypt, auto-renewing.

    Small addition, but it makes day-to-day cluster upkeep a lot less command-line-dependent. It’s not the only plumbing we’ve added recently either — we also wired this blog up to MCP so AI agents can talk to it. More about the team behind all this on our About page.

  • This Blog Now Speaks MCP: WordPress Meets the Model Context Protocol

    We just added something new under the hood: this blog now speaks MCP (Model Context Protocol), the open standard that lets AI assistants and agents talk to external tools and data in a structured way.

    We installed the official WordPress MCP Adapter plugin, which bridges WordPress’s built-in Abilities API to the MCP spec. In practice, that means MCP-aware clients can discover and invoke WordPress abilities — core, plugin, and theme functionality — programmatically, instead of needing a human to click through wp-admin.

    What this unlocks

    • A standard MCP server endpoint at /wp-json/mcp/mcp-adapter-default-server
    • Authenticated access via WordPress Application Passwords or a logged-in session
    • A foundation for future integrations — AI-assisted content workflows, tooling that reads/writes site data through a well-defined protocol instead of ad hoc scripts

    This is an early, experimental step — the plugin itself is still pre-1.0. We’ll share more as we build on top of it.

    This blog runs on infrastructure we manage ourselves — a single-node k3s cluster we keep an eye on with Headlamp, our cluster dashboard. Curious what we do with this kind of plumbing for clients? See what MashupSoft builds.