DISNUT stands for Dansday Integrated Systems and Network Unified Technology, which is a deliberately oversized name for what it is: one virtual private server, running every application I own, wired up the way a real platform is wired up. The diagram on this page is the whole thing at version 2.0.0 — not a simplified drawing of it, the actual map I work from.
The point of the exercise was never to save money. It was to find out whether one person on one box could stand up the same architecture that a team would build on managed cloud services, and then to live with the consequences honestly. This page is mostly about the consequences.
What is actually on the machine
Edge Cloudflare — DNS, CDN, proxy
Host Server 1, a single VPS
Orchestrator Coolify on Docker
Ingress Traefik reverse proxy, on Coolify's internal network
Tenants CMS PHP 8.5 / Laravel 12 admin.dansday.com
Main web Node 25 / SvelteKit 5 dansday.com
Discord bot Node 25 / SvelteKit 5 / discord.js
Data MySQL, one instance, separate databases per tenant
Redis for sessions, cache and cross-process coordination
phpMyAdmin for administration
Telemetry OpenTelemetry to SigNoz, stored in ClickHouse
Off-box Google Drive API for database backups
SMTP on shared hosting for mail and alerts
Google Workspace as the destination for alerts
Outbound OpenRouter for embeddings, Hebo as an AI gateway,
Discord API, Roblox API
From v1 to v2
Version one was about getting it running at all: a basic deployment flow, several services co-existing on a single VPS, and an initial structure to hang them on. It worked, and it was one power cut away from being a story about why you should not do this.
Version two is the same machine taken seriously. A CDN layer in front of it. Alerting, so a failure reaches me rather than waiting to be noticed. Automated database backups off the host. A real deployment pipeline instead of me typing commands. And genuine separation between the services, so that one tenant's bad afternoon is not automatically everybody's.
That is the summary. The rest of this page is what the diagram does not say out loud.
Deployment: no CI, and rules I can walk past
There is no GitHub Actions pipeline. There was, briefly — a deploy-on-release workflow was added and removed on the same day in March 2026 — and neither repository has a .github/workflows directory today. Instead, a GitHub App sends Coolify a webhook, Coolify pulls the files and builds them.
Which means the build runs on the server that is serving traffic. The Discord bot's image is a multi-stage Node build that compiles native audio modules from source — python3, make, g++, libopus-dev — before pruning down to a slim runtime. That compile competes for CPU with live requests, because there is nowhere else for it to happen. It is the clearest cost of the single-box design and it shows up on every deploy.
The repositories themselves are protected properly, and this is my favourite honest detail in the whole setup. Both have an active branch ruleset: pull requests required, one approving review, code owner review, stale reviews dismissed on push, last-push approval, review threads resolved before merge. Tags are protected too. And the bypass list contains organisation admins, with the mode set to always. I am the organisation admin. So the rules are correctly specified, and the only person they exist to constrain can step around them at will — which is exactly what happens, on every pull request, in every repository. There is also a ruleset configured for automated code-quality review on the default branch. It is disabled.
Rules without an independent enforcer are documentation. Useful documentation, but I would rather write that down than let the green shield on the repository page imply somebody reviewed my work.
The runtime shape, and why nothing is published to the host
Each tenant's container declares expose rather than ports, so no application port is bound on the host at all. Traefik reaches them over Coolify's internal Docker network and is the only way in. Containers restart unless explicitly stopped, and each has a health check on a thirty-second interval, so a hung process is replaced rather than sitting there accepting connections it cannot serve.
Configuration is entirely environment variables — database, Redis, mail, telemetry endpoint and service name — which is what makes three quite different applications deployable by the same mechanism.
Observability, on the box it observes
OpenTelemetry feeds SigNoz, which stores in ClickHouse. The instrumentation is more opinionated than it looks: the bot boots with an import that replaces console, so an ordinary console.log becomes a structured telemetry record with severity and attributes lifted out of the arguments. I did not have to teach myself to write logs a different way; the logs I already wrote became queryable.
The uncomfortable half is that SigNoz and ClickHouse run on the machine they are watching, and ClickHouse is the hungriest thing in the stack. When the host is in trouble, the tool that would explain why is in trouble with it. I know how that ends because it is the standard way this ends.
Backups and alerts leave the building, and that matters
Database backups are pushed to Google Drive through the Drive API, and both backup confirmations and unusual-activity alerts are mailed out through SMTP on a shared hosting account, arriving in my personal Google Workspace.
Two things are true about that. It is the right instinct: backups and alarms must not live on the thing they are protecting, and these do not. And the implementation is a personal Drive plus one person's mailbox, so recovery depends on a consumer account and a human reading email. I also have no record of a restore drill, which means the backup is verified only in the sense that the file arrives — that is a real gap and I am not going to describe it as a strategy.
There is one more inversion worth noticing: mail is the only piece deliberately kept off this server, and it is also the cheapest component in the diagram. The alerting path for the whole platform runs through shared hosting.
The Cloudflare lesson
Putting Cloudflare in front was the largest change in v2, and it broke something in a way I want on record because the debugging was the useful part.
The deployment dashboard stopped working — but only through the domain. Reach the same service any other way and it was fine. That shape points at exactly one thing: the layer that only exists when you come in through the domain. Cloudflare's content-optimisation features were rewriting and deferring scripts the dashboard needed, and turning them off fixed it. Nothing was wrong with the orchestrator, which is where I spent my first hour.
The general rule I took from it: when a failure appears only via the public hostname, suspect the part of the request path that only exists on the public hostname. A CDN is not a transparent layer, and it is a rewriting proxy by default.
What I would flag if this were somebody else's platform
The banner objection is the one the diagram states plainly. It says Server 1, and there is no Server 2. Every application, the database, the cache, the database admin UI, the reverse proxy and the entire observability stack share one kernel, one disk and one network interface. There is no failover and no staging environment; the production host is also the build server. A disk failure is not an incident, it is the end of every service at once, and the backups are the only actual recovery plan.
Then, smaller but real:
A web-reachable database administration interface is an extra front door on a platform whose other doors are all applications I wrote. It earns its place operationally and it needs to stay tightly constrained; that is as specific as I am willing to be on a public page about live infrastructure.
MySQL is one instance with per-tenant databases. That is separation of data, not separation of failure — a query that exhausts connections in one tenant is felt by all three.
And the whole thing depends on external services no single VPS can influence: an AI gateway, an embedding provider, Discord and Roblox. The applications handle those refusing, rate-limiting and going quiet, because they have all done so.
Why this project is on the site at all
Everything else here runs on it. This website, the CMS behind it and the Discord bot platform are the three tenants in the middle of that diagram, so the engineering on their pages is real only to the extent that this layer holds them up.
What it demonstrates is not that a single VPS is a good production architecture — it plainly is not, and the section above says why. It is that I can build the whole surface: edge, ingress, orchestration, multi-tenancy, data, cache, telemetry, backups, alerting and a deployment path, then draw it accurately and name its failure modes without waiting for one to happen. The diagram is current, which is the part most infrastructure diagrams get wrong.