Skip to content

Services

Everything we can do, and what each one delivers.

Fourteen practice areas in five groups. They are not separable in practice — a backup regime is only as good as the monitoring that notices it stopped, and an access layer is only as good as the directory behind it. They are listed apart because that is how they get scoped. Where a figure appears it was measured; where a capability is linked, it shows the figure being obtained.

01 Three areas

Monitoring & NOC

Collection that fits the equipment, alerts that reach a person, and a ticket path that opens one incident per outage.

Coverage you can prove, alerts you can trust.

Most estates are not under-instrumented. They are full of alerts nobody reads, hosts that stopped reporting without anyone noticing, and thresholds that exist only inside a database. One audit found an estate that had delivered 13 of 10,388 notification attempts in a week, with its dashboard green throughout. The work is designing collection that fits the equipment, then making the problem list mean something again.

What it delivers

  • Collection method chosen per device class — poll link state and uptime, trap BGP and OSPF neighbours — with the reason written down
  • Template strategy for multi-vendor SNMP estates: one 64-bit-counter base template, thin vendor overlays, no double-polling
  • Retention and rollup sized so history stays affordable at scale, with compression where the backend allows it
  • Proxy topology for remote sites and constrained links
  • Standing-problem audit with every false positive traced to cause
  • Alert delivery verified from the receiver's logs, not the sender's green tick
  • Trigger dependencies so one fault raises one alert, not forty
  • Streaming telemetry evaluated side by side with SNMP before anyone commits — in one lab capture, five-minute polling saw 30.9 % of the true peak
  • Metrics, logs and traces correlated instead of living in three tools

Measured

  • 112 hosts

    carried on one estate — 100 enabled, 0 unavailable — with 13,093 items and 5,008 triggers

  • 13 of 10,388

    notification attempts that reached anyone in a seven-day audit. That finding is where the work starts.

  • 40 sensors

    across 23 device templates brought to 30-second polling through one macro, with no history lost

Built on

Zabbix 6.x / 7.x Prometheus Grafana LibreNMS CheckMK OpenTelemetry Loki Tempo Mimir SNMP v2c / v3 gNMI

One outage, one ticket — and traps that survive a dead collector.

Carrier and enterprise NOCs run a monitor beside an ITSM and connect the two badly: twenty tickets for one span cut, or one ticket with a hand-typed circuit list. This practice builds the alarm-to-ticket path properly — cause-and-symptom grouping in the monitor, CMDB lookup, idempotent ticket creation — and the trap ingestion underneath it, designed for Zabbix 7 proxy groups so it keeps working when a proxy dies or a site link drops.

What it delivers

  • Alarm roll-up: one grouped event opens one incident that already lists every affected circuit as a configuration item
  • Idempotency guards — re-running returns the existing ticket; running on a symptom alarm is refused and names the cause
  • Circuits missing from the CMDB still listed on the ticket and called out in a work note, never silently dropped
  • Close and update payloads tested against the real Table API query dialect, in stock mode with no server-side customisation
  • SNMP trap collectors in a failover pair that fan out to every proxy, so proxy-group rebalancing needs no collector change
  • Trap classification compiled into a static in-memory table — zero API calls, lookups or caches in the trap path
  • SNMPv3 traps with wrong credentials rejected before processing
  • Rehearsed on a production-faithful replica before anything touches the live estate

Measured

  • 1 incident

    for 21 rolled-up alarms in a simulated span cut, with the 4 diverse-path circuits correctly left off it

  • 1.5 s

    collector failover gap on a master kill, measured; 37 of 40 traps delivered across it

  • 0 lost

    host values, and 0 collector changes, when a proxy was stopped and the group rebalanced in 26 s

Built on

Zabbix 7.x ServiceNow Table API SNMP v2c / v3 traps Python FastAPI Terraform Ansible Proxmox VE

The failover you have actually performed.

Monitoring and control planes are the things you need working during an incident, which is exactly when they are most likely to be the casualty. Clustered servers with automatic failover, a floating address so collectors follow the active node instead of going dark with it, and the database's failure domain stated plainly rather than assumed away.

What it delivers

  • Native clustering with tested, documented failover
  • A floating address the proxies follow — a proxy's server setting takes one address, so without it a clean failover blinds every proxy-monitored host
  • Failover verified end to end — primary stopped, role moved, address followed, proxy reconnected, fail-back clean
  • Database migration on a live server: MariaDB to PostgreSQL with TimescaleDB, snapshot fallback held until row counts match
  • The database's failure domain written down — a shared database is a single point of failure and is recorded as one
  • Documented recovery time, measured rather than estimated

Measured

  • < 10 s

    for the active role to move when the primary was stopped; the floating address followed and the proxy reconnected

  • 39.7 M

    history rows back-filled in 13 min 39 s during a live MariaDB to PostgreSQL migration

  • 0 errors

    across 2.08 M configuration rows moved with pgloader, row counts matched before cut-over

Built on

Zabbix HA PostgreSQL 16 TimescaleDB MariaDB pgloader keepalived Corosync

02 Four areas

Platform & continuity

The compute, storage, network and hosting underneath — with the restore performed and the failover measured.

Estates that grow without becoming unmanageable.

Design and operation of Proxmox VE estates from a single node to a multi-node cluster: guest layout, storage topology, resource limits that actually hold, and a naming and inventory discipline that keeps a hundred guests legible.

What it delivers

  • Node and cluster design sized to real workload, not to a spec sheet
  • LXC and KVM chosen per workload with the trade-off written down
  • ZFS pool layout, ARC tuning and scrub scheduling
  • Pool rebuilds with staged send/receive, stream checksums and a scrub before the old pool is destroyed
  • Capacity headroom tracked as a metric with a threshold, not a feeling
  • Autostart and power-restore policy audited — “previous state” strands a host that was shut down on battery
  • Disk-failure and pool-rebuild procedures rehearsed before they are needed
  • Templates and provisioning automation so a new guest is repeatable

Measured

  • 24 × 1.6 TB

    SAS SSDs into two RAIDZ2 vdevs; four datasets replicated with checksums verified before the old pool was destroyed

  • 22 guests

    returned to their static addresses after a rack relocation, with two live address conflicts resolved

  • 29 of 29

    published hostnames back to a non-error response after the same relocation

Built on

Proxmox VE LXC KVM / QEMU ZFS cloud-init Terraform Ceph-ready layouts

A backup you have not restored is a hypothesis.

Backup design where the deliverable is a demonstrated restore, not a green job list. One audit found six guests that had never been backed up, sixty-six snapshots that had never been verified and a retention policy that had silently never run — all behind a job list that was green. Retention modelled against how far back you would realistically need to go, deduplicated storage sized for it, and verification jobs that read the data rather than trusting the index.

What it delivers

  • Retention and pruning modelled against real recovery requirements — dry run first, then the live result compared to the prediction
  • Datastore-wide prune jobs, because per-job pruning never touches guests that were deleted or migrated
  • Deduplicated, incremental backup with garbage collection scheduled and its grace period understood
  • Verify jobs that read blocks back, not just check the catalogue
  • Documented restore procedure, performed at least once on real data and timed
  • Hypervisor credentials that can create and restore but not delete, so a compromised host cannot take its backups with it
  • The backup store's failure domain written down — including when it still shares a host with what it protects
  • Capacity alerting before the datastore fills, not after jobs start failing

Measured

  • 2,622 → 749

    snapshots once retention was made to actually run; the dry run had predicted 749

  • 48.7 s

    to restore a 1.2 GiB container from backup, timed end to end

  • Delete refused

    when the hypervisor's own token tried to remove a backup; create and restore still worked

Shown being delivered in

Built on

Proxmox Backup Server ZFS snapshots & send/recv restic rsync S3-compatible targets

Segmentation, routing and name resolution that stay predictable.

Network design and troubleshooting across the layers that break in practice: VLAN segmentation and inter-VLAN policy, multi-site overlay routing, and DNS and DHCP that agree with each other and with the inventory.

What it delivers

  • VLAN segmentation with an explicit inter-VLAN policy, default deny
  • Segmentation driven by measured traffic — mirror-port recall checked before the capture is trusted — and rolled out with a dead-man rollback
  • Multi-site WireGuard mesh with jump-host access and no inbound rules
  • Scrubbed ingress over WireGuard for protocols a CDN cannot carry, with latency and loss measured end to end
  • Authoritative internal DNS with forward and reverse records audited
  • DHCP reservations reconciled against monitoring and inventory
  • 802.1X and RADIUS authentication for wired and wireless
  • Packet-level troubleshooting when the logs have stopped being useful

Measured

  • 11.7 ms

    median end-to-end latency through a DDoS-scrubbed WireGuard ingress; p95 20.9 ms, 0 % loss

  • 45 %

    mirror-port recall measured before the capture was allowed to drive segmentation policy

  • 3 → 9

    guests brought under micro-segmentation in stages, each with a dead-man rollback

Built on

WireGuard UniFi Technitium DNS Pi-hole FreeRADIUS nftables SNMP ntopng

Sites and applications hosted on infrastructure you can inspect.

Hosting for static sites, dynamic applications and internal tools — from the origin server up through TLS, reverse proxy and edge caching. Built to be boring: hardened origins, atomic deploys, and a rollback that is one command rather than a rebuild.

What it delivers

  • Static and application hosting with atomic, reversible deploys
  • Reverse proxy and automatic TLS across many hostnames
  • Zero-inbound publishing through an outbound tunnel — no port forwards
  • Interactive routes behind single sign-on with MFA; machine routes on bearer tokens — authenticated differently, on purpose
  • Rate limiting tested from the internet, including a spoofed forwarding header that must not reset the bucket
  • Services run as a non-root user under a sandboxed systemd unit, with the data directory inaccessible to the process
  • Origin hardening: no directory listings, no stray backups, correct headers
  • Cache strategy split between immutable assets and revalidated HTML
  • Staging that mirrors production closely enough to be worth having

Measured

  • 180 + 40

    of 220 requests fired from the internet returned 200 and 429 respectively — exactly what the limit specified

  • 102 / 102

    tests passing on one hosted application, plus a 10-page, 3-viewport render check with an approval gate

Shown being delivered in

Built on

nginx Cloudflare Tunnel Nginx Proxy Manager Let's Encrypt Astro Flask systemd

03 Three areas

Security & identity

Who can reach what, proven from outside; and mail that arrives.

A numbered findings list, the fixes, and a harness that proves they held.

A read-only audit of an estate that grew organically: what is exposed, who still holds a key, which hosts patch themselves, where a credential could leak. Findings come numbered and ordered by risk. The fixes follow, and then a verification harness that re-runs every check so the improvement is proven rather than remembered — plus a secret-scanning pipeline that stays installed after the engagement ends.

What it delivers

  • External exposure checked from outside: port-forwards, tunnel hostnames against access rules, unauthenticated endpoints
  • Fleet-wide SSH key lifecycle — retired keys swept to zero, with tooling that refuses to leave a host with no key
  • API and service tokens audited for age and use; long-lived root tokens replaced with role-scoped, expiring ones
  • Unattended patching rolled out across the fleet and confirmed on each host, not from the dashboard
  • Secret scanning that fails closed: pre-commit, pre-push and a server-side pre-receive hook that scans only new blobs, so dirty history does not block every push
  • Shape-based scanner rules — credentials in URL query strings and host parts, private keys, JWTs, bearer headers — because the leaks that matter never carry a helpful variable name
  • Privileged containers and world-writable application paths found and closed
  • Every finding re-verified by a harness that is handed over with the report

Measured

  • 28 / 28

    verification checks passing on two separate re-runs after 16 numbered findings were fixed

  • 64 systems

    hardened in one key-lifecycle pass — 2 hypervisors, 55 containers, 7 VMs — with zero lockouts

  • 0 of 59

    containers were auto-patching when the audit began; 154 security updates applied in the rollout that followed

Built on

OpenSSH Gitea / GitHub hooks nftables Proxmox firewall Cloudflare Access Suricata CrowdSec Python

One sign-on, one directory, default deny.

Single sign-on and access control across an estate that grew one service at a time. A central directory as the source of identity, an OIDC provider in front of everything, and multi-factor authentication that applies to the admin interfaces as well as the pretty ones.

What it delivers

  • Central directory with group membership driving authorisation
  • OIDC single sign-on in front of services that have no auth of their own
  • Multi-factor enforced on administrative interfaces
  • Default-deny access policy with documented, reviewable exceptions
  • Every published hostname tabulated against the access rule that guards it, so a gap is a visible empty cell
  • True client address restored behind the tunnel, so per-address controls act on the visitor and not the proxy
  • Security event monitoring and log retention for after-the-fact answers

Measured

  • 35 vs 28

    published hostnames tabulated against access rules in one review — no gaps

  • 15,087

    access-layer logins reviewed in the same review, 0 unexpected

Shown being delivered in

Built on

Authelia OpenLDAP OIDC / OAuth2 Cloudflare Access fail2ban CrowdSec

Mail that arrives, and that you can prove arrived.

Self-hosted and hybrid mail: transport, mailbox storage, filtering and — the part that decides whether any of it works — deliverability. SPF, DKIM and DMARC aligned and monitored, with a relay path chosen so alert mail is not the first thing a receiver drops.

What it delivers

  • Postfix and Dovecot with LDAP-backed mailboxes and aliases
  • SPF, DKIM and DMARC published, aligned and monitored for failures
  • Spam and policy filtering tuned against real corpus, not defaults
  • Submission, relay and smarthost paths chosen per class of mail
  • Webmail and client access with TLS enforced
  • Alert mail treated as its own deliverability problem, because it is — including the resend loops that turn one event into a thousand messages

Measured

  • 1,020 → 0

    alert emails in six hours from one resend loop, traced to three compounding deduplication bugs and stopped

Shown being delivered in

Built on

Postfix Dovecot Rspamd OpenDKIM Roundcube LDAP SMTP relays

04 Two areas

Self-hosted AI

Models and agents on your own hardware, treated as production workloads.

Useful models on your own hardware, and a gateway in front.

Local inference for teams that cannot or will not send their data to a vendor. Small and mid-sized open models served on your GPUs, with a private chat interface, retrieval over your own documents, and an OpenAI-compatible gateway so existing tooling points at it without being rewritten.

What it delivers

  • Model selection and quantisation matched to the GPU you actually have
  • GPU placement measured, not assumed — pinning by device identity and stopping a model from spreading across cards
  • Private chat UI with per-user accounts behind the estate's single sign-on
  • Retrieval over internal documents and runbooks, scoped by permission
  • OpenAI-compatible endpoint so existing clients need no code change
  • Provider pooling and routing across local and hosted models by cost
  • A redaction boundary for anything sent to a hosted model: secrets and private addresses replaced with stable placeholders before egress, restored locally, output re-scanned and failing closed
  • GPU utilisation, VRAM and queue depth monitored like any other resource
  • Operational guardrails: request limits, audit logging, no silent egress

Measured

  • +36 %

    throughput on an 8B model — 86.5 to 117.5 tokens per second — from GPU placement alone, no model change

  • 2 GPUs

    shared into unprivileged containers so several accelerated workloads coexist on about 23 GB of VRAM

  • 35.1 s vs 71.6 s

    for four parallel requests at 4k and 16k context on a 12 GB card — why declared context is a capacity decision

Built on

Ollama Open WebUI llama.cpp vLLM-ready NVIDIA / NVML OpenAI-compatible APIs Vector retrieval

Coding agents treated like production workloads.

Putting AI agents to work on real codebases without handing them the keys. Routing across CLI, API and local models by what each can actually do, isolating parallel agents so their edits cannot collide, and recording every run so the question of what an agent did has an answer. The reference implementation is published as Cortex, a desktop application for driving multiple coding agents from one window.

What it delivers

  • Provider routing across CLI subscriptions, hosted APIs and local models
  • Capability checked before cost, so a chat-only model never gets shell access
  • Parallel agents isolated in git worktrees so edits cannot collide
  • Every run recorded and replayable: prompts, tool calls, edits, cost
  • Reliability measured per provider and model — success rate, latency, spend
  • Sandboxed execution with allowlists, plan mode and explicit approvals
  • Workspace checkpoints independent of git, with the diff shown before rollback
  • Retrieval over project context and notes, injected per message not per session

Built on

Tauri Rust React / TypeScript MCP Claude / Codex / Gemini CLIs OpenAI-compatible APIs Ollama SQLite

Self-hosted AI, running in this page

Models that run on your hardware, not a vendor's

Where a frontier model is genuinely the right tool, private detail is stripped on your own machines before anything is sent, and put back locally afterwards. Below is that path.

Local-first routing

runs in this page · nothing transmitted

Runs entirely in this page. Nothing you type is sent anywhere — watch the network tab if you like. Ctrl + Enter runs it.

Samples

Default sample loaded. Press Run, or type your own.

  1. 01

    Detect

    Addresses, keys and identities matched by rule, on your hardware.

  2. 02

    Tokenise

    Each value swapped for a stable placeholder. The map stays local.

  3. 03

    Route

    Simple work stays on a local model. Only tokenised text is escalated.

  4. 04

    Restore

    Real values put back into the reply, locally, after the model answers.

Stays on your hardware

SSH to 203.0.113.42 is failing since the reboot. Gateway token is ghp_EXAMPLE_NOT_A_REAL_TOKEN_00000000 and the on-call admin is [email protected].

Local map — held here, never transmitted.

PlaceholderKindReal value
<ADDR_c7963c>IPv4 address203.0.113.42
<TOKEN_14d7f6>API tokenghp_EXAMPLE_NOT_A_REAL_TOKEN_00000000
<EMAIL_3acb3b>Email address[email protected]

What leaves the building

SSH to <ADDR_c7963c> is failing since the reboot. Gateway token is <TOKEN_14d7f6> and the on-call admin is <EMAIL_3acb3b>.

Route: frontier model — "failing" reads as diagnostic work, so the tokenised text is escalated.

Simulated reply, as the model sends it:

Noted <ADDR_c7963c>, <TOKEN_14d7f6> and <EMAIL_3acb3b>. Recommendations follow.

…and as you see it, restored from the local map:

Noted 203.0.113.42, ghp_EXAMPLE_NOT_A_REAL_TOKEN_00000000 and [email protected]. Recommendations follow.

05 Two areas

Operations & advisory

Configuration you can diff, runbooks that were tested, and a lab to rehearse in.

Configuration you can diff, and a wall you can read.

The layer that keeps the rest honest: configuration in version control with a promotion path, CI that gates changes before they reach production, drift detection between what you think you run and what you run, and operations displays built on live data.

What it delivers

  • Templates and configuration under version control with idempotent, history-safe import — no item removed, renamed or retyped
  • A staging cloner that refuses any destination without an environment marker and disables every action and media channel after import
  • CI pipelines that lint, test and secret-scan before anything ships
  • Self-hosted runners for jobs that need a route into a private network
  • Drift reconciliation between inventory and what is actually monitored
  • OID triage for large MIB walks: deterministic, RFC-cited rules first, a language model only as tie-breaker
  • API automation for bulk operations, audits and reporting
  • Wall displays driven by live APIs that degrade legibly when a source dies
  • Runbooks written for the person on call at 3am, with the untested ones marked as untested
  • Documentation build-out with a publish pipeline that redacts private addresses and token patterns

Measured

  • 99.4 %

    of 8,464 walked OIDs triaged by deterministic, RFC-cited rules — 629 worth monitoring, 2,990 maybe, 4,845 skip

  • 12 of 28

    runbooks in one estate carried a tested procedure; the rest are marked never-tested rather than passed off as done

  • 14

    architectural decision records, one file each, with the reason behind every non-obvious choice

Built on

Python Bash GitHub / Gitea Actions systemd Ansible Terraform REST & JSON-RPC APIs Three.js

A safe place to practise before the change window opens.

Advisory work, and the environments that make it stick: lab estates that mirror production closely enough to rehearse in, an ITSM-shaped staging instance and simulated network devices for exercising automation, and NOC tooling practice that does not require touching anything real. Also the small end of the market — a first proper homelab or small-office estate, built once and documented.

What it delivers

  • Assessments with findings ordered by cost-to-fix against cost-to-leave
  • Lab and staging estates that mirror production topology, safely detached — with pollers zeroed and verified rather than hosts mass-disabled
  • A ServiceNow-shaped staging instance implementing the real Table API query dialect, so an integration meets the real one already tested
  • Simulated routers, carrier-Ethernet demarcation and PON devices for automation practice at zero risk
  • One-command drill and reset, so a rehearsal can be run again tomorrow
  • Homelab and small-office build-outs, from hardware selection to handover
  • Documentation and runbooks written so the estate outlives the engagement
  • Second-opinion reviews of designs, migrations and vendor proposals

Measured

  • 11 nodes

    in a containerlab NOC estate — routers, carrier-Ethernet demarcation and PON simulators — reset from snapshot in about 60 s

  • 6 VMs

    from Terraform and Ansible: two simulated sites, injectable latency, a severable inter-site link

  • 166 tests

    behind a CMDB-versus-discovery audit framework, with the parts not yet proven listed as such

Built on

Proxmox VE Terraform Ansible containerlab Zabbix test instances ServiceNow-style mock APIs NETCONF / YANG Docker Compose
Homelab design & build Three tiers, described by what is included. Quote on request. See the tiers

Engagement

How this gets scoped

Most work starts as an assessment, because it is the cheapest way to find out whether the expensive thing is necessary.

02 2–6 weeks

Build

Design and delivery of a defined system — a monitoring estate, an alarm-to-ticket integration, an access layer, a backup regime, a hosting platform — including the documentation and the handover.

  • Design agreed in writing before anything is provisioned
  • Built in version control and rehearsed on a replica, with the configuration reproducible
  • Handover session, plus runbooks for the parts that will need touching

A working system you can operate without us.

Fits when You know what you need and want it built once, properly.

03 1–4 weeks

Remediation

Targeted work on a system that exists but is not trusted: alert noise, silent gaps, failed restores, an integration that opens duplicate or thin tickets, an access layer nobody can reason about.

  • Noise removed first, so the remaining signal can be judged
  • Each fix verified against the failure it is supposed to catch
  • Changes recorded, so the estate stops being its own only record

A system whose green state means something again.

Fits when It technically works and nobody believes it.

04 Monthly retainer

Ongoing

Continuous operation and improvement, with change history, scheduled verification of the things that must not quietly break, and someone to call.

  • Scheduled verification of backups, alerting and access paths
  • Change history maintained, with a monthly written summary
  • A named contact for incidents, with agreed response expectations

The estate stays true after the project ends.

Fits when You need the estate to keep being true after the project ends.

  1. 01

    Describe what you are running

    What the estate is, and what is currently going wrong with it. No inventory spreadsheet required — a paragraph is enough to tell whether there is useful work here.

  2. 02

    A short call to scope it

    We agree which shape fits, what would be in scope, and what the finished thing has to be able to demonstrate. If the answer is that you do not need anyone, you get told that instead of a proposal.

  3. 03

    Written scope, then work

    Scope written as verifiable outcomes rather than a component list, because a component list can be delivered without the system working. Access is scoped to the task and revoked at handover.